feat(theme-editor): support to config Header's color and Settings button's color (#2263)
* feat: add color options to theme editor * feat: add default theme * refactor: optimize * feat: support to change color of UI settings * fix: fix menu background color * fix: fix color of UI settings * feat: support to set alpha * refactor: migrate style to a file * feat: support colorBgSettingsHover and colorBorderSettingsHover * feat: adapt settings color * fix: should be reset together * feat: compat old theme
This commit is contained in:
parent
7c45663cd1
commit
4f5ec0a581
@ -38,6 +38,9 @@ const CSSVariableProvider = ({ children }) => {
|
||||
document.body.style.setProperty('--colorBgScrollBarHover', colorBgScrollBarHover);
|
||||
document.body.style.setProperty('--colorBgScrollBarActive', colorBgScrollBarActive);
|
||||
document.body.style.setProperty('--colorBgDrawer', colorBgDrawer);
|
||||
document.body.style.setProperty('--colorSettings', token.colorSettings);
|
||||
document.body.style.setProperty('--colorBgSettingsHover', token.colorBgSettingsHover);
|
||||
document.body.style.setProperty('--colorBorderSettingsHover', token.colorBorderSettingsHover);
|
||||
|
||||
// 设置登录页面的背景色
|
||||
document.body.style.setProperty('background-color', token.colorBgContainer);
|
||||
@ -65,6 +68,9 @@ const CSSVariableProvider = ({ children }) => {
|
||||
token.colorPrimaryText,
|
||||
token.colorPrimaryTextActive,
|
||||
token.colorPrimaryTextHover,
|
||||
token.colorSettings,
|
||||
token.colorBgSettingsHover,
|
||||
token.colorBorderSettingsHover,
|
||||
]);
|
||||
|
||||
return children;
|
||||
|
22
packages/core/client/src/global-theme/defaultTheme.ts
Normal file
22
packages/core/client/src/global-theme/defaultTheme.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { ThemeConfig } from './type';
|
||||
|
||||
const defaultTheme: ThemeConfig = {
|
||||
name: '',
|
||||
token: {
|
||||
// 顶部导航栏
|
||||
colorPrimaryHeader: '#001529',
|
||||
colorBgHeader: '#001529',
|
||||
colorBgHeaderMenuHover: '#ffffff1a',
|
||||
colorBgHeaderMenuActive: '#ffffff1a',
|
||||
colorTextHeaderMenu: '#ffffffa6',
|
||||
colorTextHeaderMenuHover: '#ffffff',
|
||||
colorTextHeaderMenuActive: '#ffffff',
|
||||
|
||||
// UI 配置组件
|
||||
colorSettings: '#F18B62',
|
||||
colorBgSettingsHover: 'rgba(241, 139, 98, 0.06)',
|
||||
colorBorderSettingsHover: 'rgba(241, 139, 98, 0.3)',
|
||||
},
|
||||
};
|
||||
|
||||
export default defaultTheme;
|
@ -1,8 +1,8 @@
|
||||
import { ConfigProvider, theme as antdTheme, type ThemeConfig as Config } from 'antd';
|
||||
import { ConfigProvider, theme as antdTheme } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import React, { createContext, useCallback, useMemo, useRef } from 'react';
|
||||
|
||||
type ThemeConfig = Config & { name?: string; algorithm?: string | Config['algorithm'] };
|
||||
import defaultTheme from './defaultTheme';
|
||||
import { ThemeConfig } from './type';
|
||||
|
||||
interface ThemeItem {
|
||||
id: number;
|
||||
@ -27,8 +27,8 @@ export const useGlobalTheme = () => {
|
||||
return React.useContext(GlobalThemeContext);
|
||||
};
|
||||
|
||||
export const GlobalThemeProvider = ({ children, theme: defaultTheme }) => {
|
||||
const [theme, setTheme] = React.useState<ThemeConfig>(defaultTheme || { name: 'Custom theme' });
|
||||
export const GlobalThemeProvider = ({ children, theme: themeFromProps }) => {
|
||||
const [theme, setTheme] = React.useState<ThemeConfig>(themeFromProps || defaultTheme);
|
||||
const currentSettingThemeRef = useRef<ThemeConfig>(null);
|
||||
const currentEditingThemeRef = useRef<ThemeItem>(null);
|
||||
|
||||
@ -83,3 +83,6 @@ export const GlobalThemeProvider = ({ children, theme: defaultTheme }) => {
|
||||
};
|
||||
|
||||
export { default as AntdAppProvider } from './AntdAppProvider';
|
||||
export * from './type';
|
||||
export { defaultTheme };
|
||||
|
||||
|
36
packages/core/client/src/global-theme/type.ts
Normal file
36
packages/core/client/src/global-theme/type.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { MappingAlgorithm } from 'antd/es/config-provider/context';
|
||||
import { OverrideToken } from 'antd/es/theme/interface';
|
||||
import { AliasToken } from 'antd/es/theme/internal';
|
||||
|
||||
export interface CustomToken extends AliasToken {
|
||||
/** 顶部导航栏主色 */
|
||||
colorPrimaryHeader: string;
|
||||
/** 导航栏背景色 */
|
||||
colorBgHeader: string;
|
||||
/** 导航栏菜单背景色悬浮态 */
|
||||
colorBgHeaderMenuHover: string;
|
||||
/** 导航栏菜单背景色激活态 */
|
||||
colorBgHeaderMenuActive: string;
|
||||
/** 导航栏菜单文本色 */
|
||||
colorTextHeaderMenu: string;
|
||||
/** 导航栏菜单文本色悬浮态 */
|
||||
colorTextHeaderMenuHover: string;
|
||||
/** 导航栏菜单文本色激活态 */
|
||||
colorTextHeaderMenuActive: string;
|
||||
|
||||
/** UI 配置色 */
|
||||
colorSettings: string;
|
||||
/** 鼠标悬浮时显示的背景色 */
|
||||
colorBgSettingsHover: string;
|
||||
/** 鼠标悬浮时显示的边框色 */
|
||||
colorBorderSettingsHover: string;
|
||||
}
|
||||
|
||||
export interface ThemeConfig {
|
||||
name?: string;
|
||||
token?: Partial<CustomToken>;
|
||||
components?: OverrideToken;
|
||||
algorithm?: MappingAlgorithm | MappingAlgorithm[];
|
||||
hashed?: boolean;
|
||||
inherit?: boolean;
|
||||
}
|
@ -19,6 +19,7 @@ import {
|
||||
useDocumentTitle,
|
||||
useRequest,
|
||||
useSystemSettings,
|
||||
useToken,
|
||||
} from '../../../';
|
||||
import { Plugin } from '../../../application/Plugin';
|
||||
import { useCollectionManager } from '../../../collection-manager';
|
||||
@ -153,6 +154,7 @@ export const InternalAdminLayout = (props: any) => {
|
||||
const result = useSystemSettings();
|
||||
const { service } = useCollectionManager();
|
||||
const params = useParams<any>();
|
||||
const { token } = useToken();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
@ -161,10 +163,12 @@ export const InternalAdminLayout = (props: any) => {
|
||||
.ant-menu.ant-menu-dark .ant-menu-item-selected,
|
||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected,
|
||||
.ant-menu-submenu-horizontal.ant-menu-submenu-selected {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-color: ${token.colorBgHeaderMenuActive};
|
||||
color: ${token.colorTextHeaderMenuActive};
|
||||
}
|
||||
.ant-menu-dark.ant-menu-horizontal > .ant-menu-item:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-color: ${token.colorBgHeaderMenuHover};
|
||||
color: ${token.colorTextHeaderMenuHover};
|
||||
}
|
||||
|
||||
position: fixed;
|
||||
@ -174,6 +178,15 @@ export const InternalAdminLayout = (props: any) => {
|
||||
line-height: var(--nb-header-height);
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
background-color: ${token.colorBgHeader};
|
||||
|
||||
.ant-menu {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.ant-menu-item {
|
||||
color: ${token.colorTextHeaderMenu};
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
|
@ -1,3 +1,15 @@
|
||||
import { theme } from 'antd';
|
||||
const { useToken } = theme;
|
||||
import { CustomToken } from '../../../../global-theme';
|
||||
|
||||
const { useToken: useAntdToken } = theme;
|
||||
|
||||
interface Result extends ReturnType<typeof useAntdToken> {
|
||||
token: CustomToken;
|
||||
}
|
||||
|
||||
const useToken = () => {
|
||||
const result = useAntdToken();
|
||||
return result as Result;
|
||||
};
|
||||
|
||||
export { useToken };
|
||||
|
@ -2,6 +2,7 @@ import type { CSSInterpolation, CSSObject } from '@ant-design/cssinjs';
|
||||
import { useStyleRegister } from '@ant-design/cssinjs';
|
||||
import { merge } from '@formily/shared';
|
||||
import type { ComponentTokenMap, GlobalToken } from 'antd/es/theme/interface';
|
||||
import { CustomToken } from '../../../global-theme';
|
||||
import { useConfig, usePrefixCls, useToken } from './hooks';
|
||||
|
||||
export type OverrideComponent = keyof ComponentTokenMap | string;
|
||||
@ -62,7 +63,7 @@ export type UseComponentStyleResult = {
|
||||
|
||||
export const genStyleHook = <ComponentName extends OverrideComponent>(
|
||||
component: ComponentName,
|
||||
styleFn: (token: TokenWithCommonCls<GlobalToken>, props: any, info: StyleInfo) => CSSInterpolation,
|
||||
styleFn: (token: TokenWithCommonCls<CustomToken>, props: any, info: StyleInfo) => CSSInterpolation,
|
||||
) => {
|
||||
return (props?: any): UseComponentStyleResult => {
|
||||
const { theme, token, hashId } = useToken();
|
||||
@ -80,7 +81,7 @@ export const genStyleHook = <ComponentName extends OverrideComponent>(
|
||||
},
|
||||
() => {
|
||||
const componentCls = `.${prefixCls}`;
|
||||
const mergedToken: TokenWithCommonCls<GlobalToken> = merge(token, {
|
||||
const mergedToken: TokenWithCommonCls<CustomToken> = merge(token, {
|
||||
componentCls,
|
||||
prefixCls,
|
||||
iconCls: `.${iconPrefixCls}`,
|
||||
|
@ -0,0 +1,57 @@
|
||||
import { genStyleHook } from '../__builtins__';
|
||||
|
||||
const useStyles = genStyleHook('nb-action', (token) => {
|
||||
const { componentCls } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
'.renderButton': {
|
||||
position: 'relative',
|
||||
'&:hover': { '> .general-schema-designer': { display: 'block' } },
|
||||
'&.nb-action-link': {
|
||||
'> .general-schema-designer': {
|
||||
top: '-10px',
|
||||
bottom: '-10px',
|
||||
left: '-10px',
|
||||
right: '-10px',
|
||||
},
|
||||
},
|
||||
'> .general-schema-designer': {
|
||||
position: 'absolute',
|
||||
zIndex: 999,
|
||||
top: '0',
|
||||
bottom: '0',
|
||||
left: '0',
|
||||
right: '0',
|
||||
display: 'none',
|
||||
background: 'var(--colorBgSettingsHover)',
|
||||
border: '0',
|
||||
pointerEvents: 'none',
|
||||
'> .general-schema-designer-icons': {
|
||||
position: 'absolute',
|
||||
right: '2px',
|
||||
top: '2px',
|
||||
lineHeight: '16px',
|
||||
pointerEvents: 'all',
|
||||
'.ant-space-item': {
|
||||
backgroundColor: token.colorSettings,
|
||||
color: '#fff',
|
||||
lineHeight: '16px',
|
||||
width: '16px',
|
||||
paddingLeft: '1px',
|
||||
alignSelf: 'stretch',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
'.popover': {
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export default useStyles;
|
@ -1,4 +1,3 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { observer, RecursionField, useField, useFieldSchema, useForm } from '@formily/react';
|
||||
import { App, Button, Popover } from 'antd';
|
||||
import classnames from 'classnames';
|
||||
@ -17,56 +16,13 @@ import { ActionDrawer } from './Action.Drawer';
|
||||
import { ActionLink } from './Action.Link';
|
||||
import { ActionModal } from './Action.Modal';
|
||||
import { ActionPage } from './Action.Page';
|
||||
import useStyles from './Action.style';
|
||||
import { ActionContextProvider } from './context';
|
||||
import { useA } from './hooks';
|
||||
import { ComposedAction } from './types';
|
||||
import { linkageAction } from './utils';
|
||||
import { lodash } from '@nocobase/utils';
|
||||
|
||||
export const actionDesignerCss = css`
|
||||
position: relative;
|
||||
&:hover {
|
||||
> .general-schema-designer {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.nb-action-link {
|
||||
> .general-schema-designer {
|
||||
top: -10px;
|
||||
bottom: -10px;
|
||||
left: -10px;
|
||||
right: -10px;
|
||||
}
|
||||
}
|
||||
> .general-schema-designer {
|
||||
position: absolute;
|
||||
z-index: 999;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
padding-left: 1px;
|
||||
align-self: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const Action: ComposedAction = observer(
|
||||
(props: any) => {
|
||||
const {
|
||||
@ -81,6 +37,7 @@ export const Action: ComposedAction = observer(
|
||||
title,
|
||||
...others
|
||||
} = props;
|
||||
const { wrapSSR, componentCls, hashId } = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const { onClick } = useProps(props);
|
||||
const [visible, setVisible] = useState(false);
|
||||
@ -148,7 +105,7 @@ export const Action: ComposedAction = observer(
|
||||
}
|
||||
}}
|
||||
component={tarComponent || Button}
|
||||
className={classnames(actionDesignerCss, className)}
|
||||
className={classnames('renderButton', className)}
|
||||
type={props.type === 'danger' ? undefined : props.type}
|
||||
>
|
||||
{actionTitle}
|
||||
@ -157,23 +114,25 @@ export const Action: ComposedAction = observer(
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ActionContextProvider
|
||||
button={renderButton()}
|
||||
visible={visible}
|
||||
setVisible={setVisible}
|
||||
formValueChanged={formValueChanged}
|
||||
setFormValueChanged={setFormValueChanged}
|
||||
openMode={openMode}
|
||||
openSize={openSize}
|
||||
containerRefKey={containerRefKey}
|
||||
fieldSchema={fieldSchema}
|
||||
>
|
||||
{popover && <RecursionField basePath={field.address} onlyRenderProperties schema={fieldSchema} />}
|
||||
{!popover && renderButton()}
|
||||
{!popover && <div onClick={(e) => e.stopPropagation()}>{props.children}</div>}
|
||||
{element}
|
||||
</ActionContextProvider>
|
||||
return wrapSSR(
|
||||
<div className={`${componentCls} ${hashId}`}>
|
||||
<ActionContextProvider
|
||||
button={renderButton()}
|
||||
visible={visible}
|
||||
setVisible={setVisible}
|
||||
formValueChanged={formValueChanged}
|
||||
setFormValueChanged={setFormValueChanged}
|
||||
openMode={openMode}
|
||||
openSize={openSize}
|
||||
containerRefKey={containerRefKey}
|
||||
fieldSchema={fieldSchema}
|
||||
>
|
||||
{popover && <RecursionField basePath={field.address} onlyRenderProperties schema={fieldSchema} />}
|
||||
{!popover && renderButton()}
|
||||
{!popover && <div onClick={(e) => e.stopPropagation()}>{props.children}</div>}
|
||||
{element}
|
||||
</ActionContextProvider>
|
||||
</div>,
|
||||
);
|
||||
},
|
||||
{ displayName: 'Action' },
|
||||
@ -201,17 +160,7 @@ Action.Popover = observer(
|
||||
|
||||
Action.Popover.Footer = observer(
|
||||
(props) => {
|
||||
return (
|
||||
<div
|
||||
className={css`
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
`}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
return <div className="popover">{props.children}</div>;
|
||||
},
|
||||
{ displayName: 'Action.Popover.Footer' },
|
||||
);
|
||||
|
@ -10,7 +10,7 @@ const useStyles = genStyleHook('nb-association-filter-item', (token) => {
|
||||
'&:hover': { '> .general-schema-designer': { display: 'block' } },
|
||||
'&.nb-form-item:hover': {
|
||||
'> .general-schema-designer': {
|
||||
background: 'rgba(241, 139, 98, 0.06) !important',
|
||||
background: 'var(--colorBgSettingsHover) !important',
|
||||
border: '0 !important',
|
||||
top: `-${token.sizeXXS}px !important`,
|
||||
bottom: `-${token.sizeXXS}px !important`,
|
||||
@ -26,7 +26,7 @@ const useStyles = genStyleHook('nb-association-filter-item', (token) => {
|
||||
left: '0',
|
||||
right: '0',
|
||||
display: 'none',
|
||||
border: '2px solid rgba(241, 139, 98, 0.3)',
|
||||
border: '2px solid var(--colorBorderSettingsHover)',
|
||||
pointerEvents: 'none',
|
||||
'> .general-schema-designer-icons': {
|
||||
position: 'absolute',
|
||||
@ -35,7 +35,7 @@ const useStyles = genStyleHook('nb-association-filter-item', (token) => {
|
||||
lineHeight: '16px',
|
||||
pointerEvents: 'all',
|
||||
'.ant-space-item': {
|
||||
backgroundColor: '#f18b62',
|
||||
backgroundColor: 'var(--colorSettings)',
|
||||
color: '#fff',
|
||||
lineHeight: '16px',
|
||||
width: '16px',
|
||||
|
@ -39,7 +39,7 @@ export const AssociationFilter = (props) => {
|
||||
}
|
||||
&.nb-form-item:hover {
|
||||
> .general-schema-designer {
|
||||
background: rgba(241, 139, 98, 0.06) !important;
|
||||
background: var(--colorBgSettingsHover) !important;
|
||||
border: 0 !important;
|
||||
top: -5px !important;
|
||||
bottom: -5px !important;
|
||||
@ -55,7 +55,7 @@ export const AssociationFilter = (props) => {
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
border: 2px solid rgba(241, 139, 98, 0.3);
|
||||
border: 2px solid var(--colorBorderSettingsHover);
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
position: absolute;
|
||||
@ -64,7 +64,7 @@ export const AssociationFilter = (props) => {
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -21,7 +21,7 @@ export const BlockItem: React.FC<any> = (props) => {
|
||||
}
|
||||
&.nb-form-item:hover {
|
||||
> .general-schema-designer {
|
||||
background: rgba(241, 139, 98, 0.06) !important;
|
||||
background: var(--colorBgSettingsHover) !important;
|
||||
border: 0 !important;
|
||||
top: -5px !important;
|
||||
bottom: -5px !important;
|
||||
@ -37,7 +37,7 @@ export const BlockItem: React.FC<any> = (props) => {
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
border: 2px solid rgba(241, 139, 98, 0.3);
|
||||
border: 2px solid var(--colorBorderSettingsHover);
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
position: absolute;
|
||||
@ -46,7 +46,7 @@ export const BlockItem: React.FC<any> = (props) => {
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -20,7 +20,7 @@ const actionDesignerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@ -34,7 +34,7 @@ const actionDesignerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -103,8 +103,8 @@ const SaveConditions = () => {
|
||||
<Button
|
||||
type={'dashed'}
|
||||
className={css`
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
`}
|
||||
onClick={() => {
|
||||
const defaultValue = { ...form.values.filter };
|
||||
|
@ -16,8 +16,8 @@ export const SaveDefaultValue = (props) => {
|
||||
return (
|
||||
<Button
|
||||
className={css`
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
`}
|
||||
type={'dashed'}
|
||||
onClick={() => {
|
||||
|
@ -34,7 +34,7 @@ const designerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
@ -44,7 +44,7 @@ const designerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -18,7 +18,7 @@ const useStyles = genStyleHook('nb-grid', (token) => {
|
||||
cursor: 'col-resize',
|
||||
},
|
||||
'&:hover': {
|
||||
'&::before': { background: 'rgba(241, 139, 98, 0.06) !important' },
|
||||
'&::before': { background: 'var(--colorBgSettingsHover) !important' },
|
||||
},
|
||||
width: token.marginLG,
|
||||
height: '100%',
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { useDndContext, useDndMonitor, useDraggable, useDroppable } from '@dnd-kit/core';
|
||||
import { RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
@ -16,6 +17,7 @@ const breakRemoveOnGrid = (s: Schema) => s['x-component'] === 'Grid';
|
||||
const breakRemoveOnRow = (s: Schema) => s['x-component'] === 'Grid.Row';
|
||||
|
||||
const ColDivider = (props) => {
|
||||
const { token } = useToken();
|
||||
const dragIdRef = useRef<string | null>(null);
|
||||
|
||||
const { isOver, setNodeRef } = useDroppable({
|
||||
@ -28,7 +30,7 @@ const ColDivider = (props) => {
|
||||
const droppableStyle = useMemo(() => {
|
||||
if (!isOver) return {};
|
||||
return {
|
||||
backgroundColor: 'rgba(241, 139, 98, .1)',
|
||||
backgroundColor: new TinyColor(token.colorSettings).setAlpha(0.1).toHex8String(),
|
||||
};
|
||||
}, [isOver]);
|
||||
|
||||
@ -161,6 +163,7 @@ const ColDivider = (props) => {
|
||||
};
|
||||
|
||||
const RowDivider = (props) => {
|
||||
const { token } = useToken();
|
||||
const { isOver, setNodeRef } = useDroppable({
|
||||
id: props.id,
|
||||
data: props.data,
|
||||
@ -176,7 +179,7 @@ const RowDivider = (props) => {
|
||||
|
||||
return {
|
||||
zIndex: active ? 1000 : -1,
|
||||
backgroundColor: 'rgba(241, 139, 98, .1)',
|
||||
backgroundColor: new TinyColor(token.colorSettings).setAlpha(0.1).toHex8String(),
|
||||
};
|
||||
}, [active, isOver]);
|
||||
|
||||
|
@ -18,7 +18,7 @@ const titleCss = css`
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
background: #f18b62;
|
||||
background: var(--colorSettings);
|
||||
color: #fff;
|
||||
padding: 0 5px;
|
||||
line-height: 16px;
|
||||
|
@ -17,7 +17,7 @@ const useStyles = genStyleHook('nb-list', (token) => {
|
||||
left: '0',
|
||||
right: '0',
|
||||
display: 'none',
|
||||
background: 'rgba(241, 139, 98, 0.06)',
|
||||
background: 'var(--colorBgSettingsHover)',
|
||||
border: '0',
|
||||
pointerEvents: 'none',
|
||||
'> .general-schema-designer-icons': {
|
||||
@ -27,7 +27,7 @@ const useStyles = genStyleHook('nb-list', (token) => {
|
||||
lineHeight: '16px',
|
||||
pointerEvents: 'all',
|
||||
'.ant-space-item': {
|
||||
backgroundColor: '#f18b62',
|
||||
backgroundColor: 'var(--colorSettings)',
|
||||
color: '#fff',
|
||||
lineHeight: '16px',
|
||||
width: '16px',
|
||||
|
@ -48,7 +48,7 @@ const subMenuDesignerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
@ -58,7 +58,7 @@ const subMenuDesignerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
@ -99,7 +99,7 @@ const designerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
> .general-schema-designer-icons {
|
||||
@ -109,7 +109,7 @@ const designerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -30,7 +30,7 @@ export const useStyles = genStyleHook('nb-page', (token) => {
|
||||
lineHeight: '16px',
|
||||
pointerEvents: 'all',
|
||||
'.ant-space-item': {
|
||||
backgroundColor: '#f18b62',
|
||||
backgroundColor: 'var(--colorSettings)',
|
||||
color: '#fff',
|
||||
lineHeight: '16px',
|
||||
width: '16px',
|
||||
@ -57,8 +57,8 @@ export const useStyles = genStyleHook('nb-page', (token) => {
|
||||
},
|
||||
|
||||
'.addTabBtn': {
|
||||
borderColor: 'rgb(241, 139, 98) !important',
|
||||
color: 'rgb(241, 139, 98) !important',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
},
|
||||
|
||||
'.designerCss': {
|
||||
@ -80,7 +80,7 @@ export const useStyles = genStyleHook('nb-page', (token) => {
|
||||
left: '0',
|
||||
right: '0',
|
||||
display: 'none',
|
||||
background: 'rgba(241, 139, 98, 0.06)',
|
||||
background: 'var(--colorBgSettingsHover)',
|
||||
border: '0',
|
||||
pointerEvents: 'none',
|
||||
'> .general-schema-designer-icons': {
|
||||
@ -90,7 +90,7 @@ export const useStyles = genStyleHook('nb-page', (token) => {
|
||||
lineHeight: '16px',
|
||||
pointerEvents: 'all',
|
||||
'.ant-space-item': {
|
||||
backgroundColor: '#f18b62',
|
||||
backgroundColor: 'var(--colorSettings)',
|
||||
color: '#fff',
|
||||
lineHeight: '16px',
|
||||
width: '16px',
|
||||
|
@ -18,7 +18,7 @@ export const designerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06) !important;
|
||||
background: var(--colorBgSettingsHover) !important;
|
||||
border: 0 !important;
|
||||
top: -16px !important;
|
||||
bottom: -16px !important;
|
||||
@ -32,7 +32,7 @@ export const designerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DeleteOutlined, MenuOutlined } from '@ant-design/icons';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
|
||||
import { css } from '@emotion/css';
|
||||
import { ArrayField, Field } from '@formily/core';
|
||||
@ -113,27 +114,33 @@ const useTableColumns = (props) => {
|
||||
return tableColumns;
|
||||
};
|
||||
|
||||
const topActiveClass = css`
|
||||
& > td {
|
||||
border-top: 2px solid rgba(241, 139, 98, 0.6) !important;
|
||||
}
|
||||
`;
|
||||
const bottomActiveClass = css`
|
||||
& > td {
|
||||
border-bottom: 2px solid rgba(241, 139, 98, 0.6) !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const SortableRow = (props) => {
|
||||
const { token } = useToken();
|
||||
const id = props['data-row-key']?.toString();
|
||||
const { setNodeRef, isOver, active, over } = useSortable({
|
||||
id,
|
||||
});
|
||||
|
||||
const classObj = useMemo(() => {
|
||||
const borderColor = new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String();
|
||||
return {
|
||||
topActiveClass: css`
|
||||
& > td {
|
||||
border-top: 2px solid ${borderColor} !important;
|
||||
}
|
||||
`,
|
||||
bottomActiveClass: css`
|
||||
& > td {
|
||||
border-bottom: 2px solid ${borderColor} !important;
|
||||
}
|
||||
`,
|
||||
};
|
||||
}, [token.colorSettings]);
|
||||
|
||||
const className =
|
||||
(active?.data.current?.sortable.index ?? -1) > (over?.data.current?.sortable?.index ?? -1)
|
||||
? topActiveClass
|
||||
: bottomActiveClass;
|
||||
? classObj.topActiveClass
|
||||
: classObj.bottomActiveClass;
|
||||
|
||||
return (
|
||||
<tr
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { MenuOutlined } from '@ant-design/icons';
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { css } from '@emotion/css';
|
||||
import { ArrayField, Field } from '@formily/core';
|
||||
import {
|
||||
@ -15,6 +16,7 @@ import React, { useContext, useState } from 'react';
|
||||
import ReactDragListView from 'react-drag-listview';
|
||||
import { DndContext } from '../..';
|
||||
import { RecordIndexProvider, RecordProvider, useRequest, useSchemaInitializer } from '../../../';
|
||||
import { useToken } from '../__builtins__';
|
||||
|
||||
const isColumnComponent = (schema: Schema) => {
|
||||
return schema['x-component']?.endsWith('.Column') > -1;
|
||||
@ -149,6 +151,7 @@ const useDefAction = () => {
|
||||
|
||||
export const TableArray: React.FC<any> = observer(
|
||||
(props) => {
|
||||
const { token } = useToken();
|
||||
const field = useField<ArrayField>();
|
||||
const columns = useTableColumns();
|
||||
const {
|
||||
@ -270,7 +273,7 @@ export const TableArray: React.FC<any> = observer(
|
||||
await move(from, to);
|
||||
}}
|
||||
lineClassName={css`
|
||||
border-bottom: 2px solid rgba(241, 139, 98, 0.6) !important;
|
||||
border-bottom: 2px solid ${new TinyColor(token.colorSettings).setAlpha(0.6).toHex8String()} !important;
|
||||
`}
|
||||
>
|
||||
<Table
|
||||
|
@ -18,7 +18,7 @@ export const designerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06) !important;
|
||||
background: var(--colorBgSettingsHover) !important;
|
||||
border: 0 !important;
|
||||
top: -16px !important;
|
||||
bottom: -16px !important;
|
||||
@ -32,7 +32,7 @@ export const designerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||
import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd';
|
||||
import { Tabs as AntdTabs, TabPaneProps, TabsProps } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from '../../../icon';
|
||||
import { useSchemaInitializer } from '../../../schema-initializer';
|
||||
import { DndContext, SortableItem } from '../../common';
|
||||
@ -68,7 +67,7 @@ const designerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@ -82,7 +81,7 @@ const designerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
import { useDraggable, useDroppable } from '@dnd-kit/core';
|
||||
import { cx } from '@emotion/css';
|
||||
import { Schema, observer, useField, useFieldSchema } from '@formily/react';
|
||||
import React, { HTMLAttributes, createContext, useContext } from 'react';
|
||||
import { useToken } from '../../antd/__builtins__';
|
||||
|
||||
export const DraggableContext = createContext(null);
|
||||
export const SortableContext = createContext(null);
|
||||
@ -21,12 +23,15 @@ export const SortableProvider = (props) => {
|
||||
|
||||
export const Sortable = (props: any) => {
|
||||
const { component, overStyle, style, children, openMode, ...others } = props;
|
||||
const { token } = useToken();
|
||||
const { draggable, droppable } = useContext(SortableContext);
|
||||
const { isOver, setNodeRef } = droppable;
|
||||
const droppableStyle = { ...style };
|
||||
|
||||
if (isOver && draggable?.active?.id !== droppable?.over?.id) {
|
||||
droppableStyle[component === 'a' ? 'color' : 'background'] = 'rgba(241, 139, 98, .15)';
|
||||
droppableStyle[component === 'a' ? 'color' : 'background'] = new TinyColor(token.colorSettings)
|
||||
.setAlpha(0.15)
|
||||
.toHex8String();
|
||||
Object.assign(droppableStyle, overStyle);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ export const DesignableSwitch = () => {
|
||||
const { t } = useTranslation();
|
||||
const style = {};
|
||||
if (designable) {
|
||||
style['backgroundColor'] = '#f18b62';
|
||||
style['backgroundColor'] = 'var(--colorSettings)';
|
||||
}
|
||||
|
||||
// 快捷键切换编辑状态
|
||||
|
@ -69,8 +69,8 @@ SchemaInitializer.Button = observer(
|
||||
<Button
|
||||
type={'dashed'}
|
||||
style={{
|
||||
borderColor: '#f18b62',
|
||||
color: '#f18b62',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
...style,
|
||||
}}
|
||||
{...others}
|
||||
@ -329,8 +329,8 @@ SchemaInitializer.ActionModal = function ActionModal(props: SchemaInitializerAct
|
||||
'x-component-props': {
|
||||
icon: 'PlusOutlined',
|
||||
style: {
|
||||
borderColor: 'rgb(241, 139, 98)',
|
||||
color: 'rgb(241, 139, 98)',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
},
|
||||
title: buttonText,
|
||||
type: 'dashed',
|
||||
|
@ -54,8 +54,8 @@ export const TabPaneInitializers = (props?: any) => {
|
||||
'x-component-props': {
|
||||
icon: 'PlusOutlined',
|
||||
style: {
|
||||
borderColor: 'rgb(241, 139, 98)',
|
||||
color: 'rgb(241, 139, 98)',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
},
|
||||
type: 'dashed',
|
||||
},
|
||||
|
@ -26,7 +26,7 @@ export const actionDesignerCss = css`
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
background: rgba(241, 139, 98, 0.06);
|
||||
background: var(--colorBgSettingsHover);
|
||||
border: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
@ -40,7 +40,7 @@ export const actionDesignerCss = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -13,7 +13,7 @@ const titleCss = css`
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
/* background: #f18b62;
|
||||
/* background: var(--colorSettings);
|
||||
color: #fff; */
|
||||
padding: 0;
|
||||
line-height: 16px;
|
||||
@ -25,7 +25,7 @@ const titleCss = css`
|
||||
.title-tag {
|
||||
padding: 0 3px;
|
||||
border-radius: 2px;
|
||||
background: #f18b62;
|
||||
background: var(--colorSettings);
|
||||
color: #fff;
|
||||
display: block;
|
||||
}
|
||||
|
@ -1,3 +1,15 @@
|
||||
import { theme } from 'antd';
|
||||
import { CustomToken } from '../global-theme';
|
||||
|
||||
export const { useToken } = theme;
|
||||
const { useToken: useAntdToken } = theme;
|
||||
|
||||
interface Result extends ReturnType<typeof useAntdToken> {
|
||||
token: CustomToken;
|
||||
}
|
||||
|
||||
const useToken = () => {
|
||||
const result = useAntdToken();
|
||||
return result as Result;
|
||||
};
|
||||
|
||||
export { useToken };
|
||||
|
@ -74,11 +74,11 @@ export const useShared = () => {
|
||||
'x-component': 'ArrayItems.Addition',
|
||||
'x-component-props': {
|
||||
className: css`
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
&.ant-btn-dashed:hover {
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
@ -79,11 +79,11 @@ export const useShared = () => {
|
||||
'x-component': 'ArrayItems.Addition',
|
||||
'x-component-props': {
|
||||
className: css`
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
&.ant-btn-dashed:hover {
|
||||
border-color: rgb(241, 139, 98);
|
||||
color: rgb(241, 139, 98);
|
||||
border-color: var(--colorSettings);
|
||||
color: var(--colorSettings);
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
@ -30,8 +30,8 @@ export const ContainerDesigner = () => {
|
||||
title={
|
||||
<Button
|
||||
style={{
|
||||
borderColor: 'rgb(241, 139, 98)',
|
||||
color: 'rgb(241, 139, 98)',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
width: '100%',
|
||||
}}
|
||||
icon={<MenuOutlined />}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { GeneralSchemaDesigner, SchemaSettings, useDesignable } from '@nocobase/client';
|
||||
import { MenuOutlined } from '@ant-design/icons';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import { SchemaSettings, useDesignable } from '@nocobase/client';
|
||||
import { Button } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from '../../../../locale';
|
||||
import { Button } from 'antd';
|
||||
import { useFieldSchema, useField } from '@formily/react';
|
||||
|
||||
export const MenuDesigner: React.FC = (props) => {
|
||||
const { t } = useTranslation();
|
||||
@ -20,8 +20,8 @@ export const MenuDesigner: React.FC = (props) => {
|
||||
title={
|
||||
<Button
|
||||
style={{
|
||||
borderColor: 'rgb(241, 139, 98)',
|
||||
color: 'rgb(241, 139, 98)',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
}}
|
||||
icon={<MenuOutlined />}
|
||||
type="dashed"
|
||||
|
@ -26,8 +26,8 @@ export const PageDesigner = (props) => {
|
||||
title={
|
||||
<Button
|
||||
style={{
|
||||
borderColor: 'rgb(241, 139, 98)',
|
||||
color: 'rgb(241, 139, 98)',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
width: '100%',
|
||||
}}
|
||||
icon={<MenuOutlined />}
|
||||
|
@ -43,7 +43,7 @@ const commonDesignerCSS = css`
|
||||
line-height: 16px;
|
||||
pointer-events: all;
|
||||
.ant-space-item {
|
||||
background-color: #f18b62;
|
||||
background-color: var(--colorSettings);
|
||||
color: #fff;
|
||||
line-height: 16px;
|
||||
width: 16px;
|
||||
|
@ -16,6 +16,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nocobase/server": "0.11.0-alpha.1",
|
||||
"@nocobase/test": "0.11.0-alpha.1"
|
||||
"@nocobase/test": "0.11.0-alpha.1",
|
||||
"@ctrl/tinycolor": "^3.6.0"
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,20 @@ const useControlledTheme: UseControlledTheme = ({ theme: customTheme, defaultThe
|
||||
const handleResetTheme = (path: string[]) => {
|
||||
let newConfig = { ...theme.config };
|
||||
newConfig = deepUpdateObj(newConfig, path, getValueByPath(themeRef.current?.config, path));
|
||||
|
||||
if (path[1] === 'colorSettings') {
|
||||
newConfig = deepUpdateObj(
|
||||
newConfig,
|
||||
['token', 'colorBgSettingsHover'],
|
||||
getValueByPath(themeRef.current?.config, ['token', 'colorBgSettingsHover']),
|
||||
);
|
||||
newConfig = deepUpdateObj(
|
||||
newConfig,
|
||||
['token', 'colorBorderSettingsHover'],
|
||||
getValueByPath(themeRef.current?.config, ['token', 'colorBorderSettingsHover']),
|
||||
);
|
||||
}
|
||||
|
||||
handleSetTheme({ ...theme, config: newConfig }, path);
|
||||
};
|
||||
|
||||
|
@ -2,7 +2,7 @@ import type { AliasToken } from '../interface';
|
||||
import type { TokenTree } from './interface';
|
||||
import { seedRelatedAlias, seedRelatedMap } from './TokenRelation';
|
||||
|
||||
const category: TokenTree<keyof AliasToken> = [
|
||||
const category: TokenTree<keyof AliasToken | string> = [
|
||||
{
|
||||
name: '颜色',
|
||||
nameEn: 'Color',
|
||||
@ -15,7 +15,8 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
name: '品牌色',
|
||||
nameEn: 'Brand Color',
|
||||
desc: '品牌色是体现产品特性和传播理念最直观的视觉元素之一。在你完成品牌主色的选取之后,我们会自动帮你生成一套完整的色板,并赋予它们有效的设计语义。',
|
||||
descEn: '',
|
||||
descEn:
|
||||
'Brand color is one of the most direct visual elements to reflect the characteristics and communication of the product. After you have selected the brand color, we will automatically generate a complete color palette and assign it effective design semantics.',
|
||||
seedToken: ['colorPrimary'],
|
||||
mapToken: seedRelatedMap.colorPrimary,
|
||||
aliasToken: seedRelatedAlias.colorPrimary,
|
||||
@ -25,8 +26,9 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
type: 'Color',
|
||||
name: '成功色',
|
||||
nameEn: 'Success Color',
|
||||
desc: '',
|
||||
descEn: '',
|
||||
desc: '用于表示操作成功的 Token 序列,如 Result、Progress 等组件会使用该组梯度变量。',
|
||||
descEn:
|
||||
'Used to represent the token sequence of operation success, such as Result, Progress and other components will use these map tokens.',
|
||||
seedToken: ['colorSuccess'],
|
||||
mapToken: seedRelatedMap.colorSuccess,
|
||||
aliasToken: seedRelatedAlias.colorSuccess,
|
||||
@ -36,8 +38,9 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
type: 'Color',
|
||||
name: '警戒色',
|
||||
nameEn: 'Warning Color',
|
||||
desc: '',
|
||||
descEn: '',
|
||||
desc: '用于表示操作警告的 Token 序列,如 Notification、 Alert等警告类组件或 Input 输入类等组件会使用该组梯度变量。',
|
||||
descEn:
|
||||
'Used to represent the warning map token, such as Notification, Alert, etc. Alert or Control component(like Input) will use these map tokens.',
|
||||
seedToken: ['colorWarning'],
|
||||
mapToken: seedRelatedMap.colorWarning,
|
||||
aliasToken: seedRelatedAlias.colorWarning,
|
||||
@ -47,8 +50,9 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
type: 'Color',
|
||||
name: '错误色',
|
||||
nameEn: 'Error Color',
|
||||
desc: '',
|
||||
descEn: '',
|
||||
desc: '用于表示操作失败的 Token 序列,如失败按钮、错误状态提示(Result)组件等。',
|
||||
descEn:
|
||||
'Used to represent the visual elements of the operation failure, such as the error Button, error Result component, etc.',
|
||||
seedToken: ['colorError'],
|
||||
mapToken: seedRelatedMap.colorError,
|
||||
aliasToken: seedRelatedAlias.colorError,
|
||||
@ -58,8 +62,9 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
type: 'Color',
|
||||
name: '信息色',
|
||||
nameEn: 'Info Color',
|
||||
desc: '',
|
||||
descEn: '',
|
||||
desc: '用于表示操作信息的 Token 序列,如 Alert 、Tag、 Progress 等组件都有用到该组梯度变量。',
|
||||
descEn:
|
||||
'Used to represent the operation information of the Token sequence, such as Alert, Tag, Progress, and other components use these map tokens.',
|
||||
seedToken: ['colorInfo'],
|
||||
mapToken: seedRelatedMap.colorInfo,
|
||||
aliasToken: seedRelatedAlias.colorInfo,
|
||||
@ -70,7 +75,8 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
name: '中性色',
|
||||
nameEn: 'Neutral Color',
|
||||
desc: '中性色主要被大量的应用在界面的文字、背景、边框和填充的 4 种场景。合理地选择中性色能够令页面信息具备良好的主次关系,助力阅读体验。',
|
||||
descEn: '',
|
||||
descEn:
|
||||
'Neutral color is mainly applied to the four scenarios of text, background, border and fill in the interface. Reasonable selection of neutral colors can make the page information have a good primary and secondary relationship, and help the reading experience.',
|
||||
seedToken: ['colorTextBase', 'colorBgBase'],
|
||||
mapToken: seedRelatedMap.colorTextBase?.concat(seedRelatedMap.colorBgBase ?? []),
|
||||
aliasToken: seedRelatedAlias.colorTextBase?.concat(seedRelatedAlias.colorBgBase ?? []),
|
||||
@ -78,6 +84,36 @@ const category: TokenTree<keyof AliasToken> = [
|
||||
'你可以利用 Alias Token 来精准控制部分组件的效果。例如 Input 、InputNumber、Select 等Control 类组件都共享了相同的 controlXX token 。只需修改值,即可实现不改变 Button 的情况下,修改 Control 类组件的效果。',
|
||||
mapTokenGroups: ['text', 'border', 'fill', 'background'],
|
||||
},
|
||||
{
|
||||
key: 'headerColor',
|
||||
type: 'Color',
|
||||
name: '导航色',
|
||||
nameEn: 'Header Color',
|
||||
desc: '只会影响页面顶部的导航栏',
|
||||
descEn: 'Only affects the navigation bar at the top of the page.',
|
||||
// seedToken: ['colorPrimaryHeader'],
|
||||
seedToken: [
|
||||
'colorBgHeader',
|
||||
'colorBgHeaderMenuHover',
|
||||
'colorBgHeaderMenuActive',
|
||||
'colorTextHeaderMenu',
|
||||
'colorTextHeaderMenuHover',
|
||||
'colorTextHeaderMenuActive',
|
||||
],
|
||||
seedTokenAlpha: true,
|
||||
},
|
||||
{
|
||||
key: 'settingsColor',
|
||||
type: 'Color',
|
||||
name: 'UI 配置色',
|
||||
nameEn: 'UI Settings Color',
|
||||
desc: '用于更改 UI 配置组件的颜色',
|
||||
descEn: 'Used to change the color of the UI Settings component.',
|
||||
// seedToken: ['colorPrimarySettings'],
|
||||
seedToken: ['colorSettings'],
|
||||
seedTokenAlpha: true,
|
||||
mapToken: ['colorBgSettingsHover', 'colorBorderSettingsHover'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -34,6 +34,8 @@ export type TokenGroup<T> = {
|
||||
|
||||
// Seed token
|
||||
seedToken?: T[];
|
||||
/** make seedToken can be alpha */
|
||||
seedTokenAlpha?: boolean;
|
||||
mapToken?: T[];
|
||||
aliasToken?: T[];
|
||||
|
||||
|
@ -3,7 +3,6 @@ import { Button, Checkbox, Collapse, ConfigProvider, Popover, Switch, Tooltip, T
|
||||
import type { MutableTheme } from 'antd-token-previewer';
|
||||
import type { ThemeConfig } from 'antd/es/config-provider/context';
|
||||
import seed from 'antd/es/theme/themes/seed';
|
||||
import tokenMeta from 'antd/lib/version/token-meta.json';
|
||||
import classNames from 'classnames';
|
||||
import type { FC } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
@ -21,6 +20,8 @@ import makeStyle from '../utils/makeStyle';
|
||||
import InputNumberPlus from './InputNumberPlus';
|
||||
import TokenDetail from './TokenDetail';
|
||||
import TokenPreview from './TokenPreview';
|
||||
import calcCustomToken from './calcCustomToken';
|
||||
import tokenMeta from './token-meta.json';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
@ -230,6 +231,7 @@ export type SeedTokenProps = {
|
||||
theme: MutableTheme;
|
||||
tokenName: string;
|
||||
disabled?: boolean;
|
||||
alpha?: boolean;
|
||||
};
|
||||
|
||||
const getSeedValue = (config: ThemeConfig, token: string) => {
|
||||
@ -256,7 +258,7 @@ const seedRange: Record<string, { min: number; max: number }> = {
|
||||
},
|
||||
};
|
||||
|
||||
const SeedTokenPreview: FC<SeedTokenProps> = ({ theme, tokenName, disabled }) => {
|
||||
const SeedTokenPreview: FC<SeedTokenProps> = ({ theme, tokenName, disabled, alpha }) => {
|
||||
const tokenPath = ['token', tokenName];
|
||||
const [tokenValue, setTokenValue] = useState(getSeedValue(theme.config, tokenName));
|
||||
const locale = useLocale();
|
||||
@ -267,7 +269,7 @@ const SeedTokenPreview: FC<SeedTokenProps> = ({ theme, tokenName, disabled }) =>
|
||||
...theme.config,
|
||||
token: {
|
||||
...theme.config.token,
|
||||
[tokenName]: newValue,
|
||||
...calcCustomToken(tokenName, newValue),
|
||||
},
|
||||
},
|
||||
['token', tokenName],
|
||||
@ -305,7 +307,7 @@ const SeedTokenPreview: FC<SeedTokenProps> = ({ theme, tokenName, disabled }) =>
|
||||
trigger="click"
|
||||
placement="bottomRight"
|
||||
overlayInnerStyle={{ padding: 0 }}
|
||||
content={<ColorPanel color={tokenValue} onChange={handleChange} style={{ border: 'none' }} />}
|
||||
content={<ColorPanel color={tokenValue} onChange={handleChange} style={{ border: 'none' }} alpha={alpha} />}
|
||||
>
|
||||
<div
|
||||
className="token-panel-pro-token-collapse-seed-block-sample-card"
|
||||
@ -643,6 +645,7 @@ const TokenContent: FC<ColorTokenContentProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
<SeedTokenPreview
|
||||
alpha={!!group.seedTokenAlpha}
|
||||
theme={theme}
|
||||
tokenName={seedToken}
|
||||
disabled={seedToken === 'colorInfo' && infoFollowPrimary}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Tooltip } from 'antd';
|
||||
import type { MutableTheme } from 'antd-token-previewer';
|
||||
import tokenMeta from 'antd/lib/version/token-meta.json';
|
||||
import classNames from 'classnames';
|
||||
import type { FC } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
@ -13,6 +12,7 @@ import getDesignToken from '../utils/getDesignToken';
|
||||
import getValueByPath from '../utils/getValueByPath';
|
||||
import makeStyle from '../utils/makeStyle';
|
||||
import { getRelatedComponents } from '../utils/statistic';
|
||||
import tokenMeta from './token-meta.json';
|
||||
|
||||
const useStyle = makeStyle('TokenDetail', (token) => ({
|
||||
'.token-panel-token-detail': {
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { TinyColor } from '@ctrl/tinycolor';
|
||||
|
||||
const calcCustomToken = (name: string, value: any) => {
|
||||
if (name === 'colorSettings') {
|
||||
const color = new TinyColor(value);
|
||||
return {
|
||||
colorSettings: value,
|
||||
colorBgSettingsHover: color.setAlpha(0.06).toHex8String(),
|
||||
colorBorderSettingsHover: color.setAlpha(0.3).toHex8String(),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
[name]: value,
|
||||
};
|
||||
};
|
||||
|
||||
export default calcCustomToken;
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
import { useAPIClient, useCurrentUserContext, useGlobalTheme, useSystemSettings } from '@nocobase/client';
|
||||
import { defaultTheme, useAPIClient, useCurrentUserContext, useGlobalTheme, useSystemSettings } from '@nocobase/client';
|
||||
import { error } from '@nocobase/utils/client';
|
||||
import { Spin } from 'antd';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
@ -50,13 +50,17 @@ const InitializeTheme: React.FC = ({ children }) => {
|
||||
const theme = data?.find((item) => item.id === themeId.current);
|
||||
if (theme) {
|
||||
setTheme(theme.config);
|
||||
api.auth.setOption('theme', JSON.stringify(Object.assign({ ...theme }, { config: changeAlgorithmFromFunctionToString(theme.config) })))
|
||||
api.auth.setOption(
|
||||
'theme',
|
||||
JSON.stringify(Object.assign({ ...theme }, { config: changeAlgorithmFromFunctionToString(theme.config) })),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setTheme({});
|
||||
setTheme(defaultTheme);
|
||||
api.auth.setOption('theme', null);
|
||||
}
|
||||
}, [
|
||||
api.auth,
|
||||
currentUser?.data?.data?.systemSettings?.themeId,
|
||||
data,
|
||||
run,
|
||||
|
@ -7,6 +7,7 @@ import { ThemeConfig, ThemeItem } from '../../types';
|
||||
import { Primary } from '../antd-token-previewer';
|
||||
import { useUpdateThemeSettings } from '../hooks/useUpdateThemeSettings';
|
||||
import { useTranslation } from '../locale';
|
||||
import compatOldTheme from '../utils/compatOldTheme';
|
||||
import { useCurrentThemeId } from './InitializeTheme';
|
||||
import { useThemeEditorContext } from './ThemeEditorProvider';
|
||||
|
||||
@ -178,7 +179,7 @@ const ThemeCard = (props: Props) => {
|
||||
const handleEdit = useCallback(() => {
|
||||
setCurrentSettingTheme(currentTheme);
|
||||
setCurrentEditingTheme(item);
|
||||
setTheme(item.config);
|
||||
setTheme(compatOldTheme(item.config));
|
||||
setOpen(true);
|
||||
}, [item, setCurrentEditingTheme, setCurrentSettingTheme, setOpen, setTheme, currentTheme]);
|
||||
|
||||
@ -277,7 +278,14 @@ const ThemeCard = (props: Props) => {
|
||||
|
||||
const cardStyle = useMemo(() => {
|
||||
if (getCurrentEditingTheme()?.id === item.id) {
|
||||
return { cursor: 'default', width: 240, height: 240, overflow: 'hidden', outline: '1px solid #f18b62', ...style };
|
||||
return {
|
||||
cursor: 'default',
|
||||
width: 240,
|
||||
height: 240,
|
||||
overflow: 'hidden',
|
||||
outline: '1px solid var(--colorSettings)',
|
||||
...style,
|
||||
};
|
||||
}
|
||||
return { cursor: 'default', width: 240, height: 240, overflow: 'hidden', ...style };
|
||||
}, [getCurrentEditingTheme, item.id, style]);
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { useGlobalTheme, useToken } from '@nocobase/client';
|
||||
import { defaultTheme, useGlobalTheme, useToken } from '@nocobase/client';
|
||||
import { App, Button, Space } from 'antd';
|
||||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from '../locale';
|
||||
import compatOldTheme from '../utils/compatOldTheme';
|
||||
import { useThemeEditorContext } from './ThemeEditorProvider';
|
||||
|
||||
const ToEditTheme = () => {
|
||||
@ -33,7 +34,7 @@ const ToEditTheme = () => {
|
||||
type={'primary'}
|
||||
onClick={() => {
|
||||
setCurrentSettingTheme(theme);
|
||||
setTheme({});
|
||||
setTheme(compatOldTheme(defaultTheme));
|
||||
setOpen(true);
|
||||
m.destroy();
|
||||
}}
|
||||
@ -52,8 +53,8 @@ const ToEditTheme = () => {
|
||||
width: 240,
|
||||
height: 240,
|
||||
borderRadius: token.borderRadiusLG,
|
||||
borderColor: '#f18b62',
|
||||
color: '#f18b62',
|
||||
borderColor: 'var(--colorSettings)',
|
||||
color: 'var(--colorSettings)',
|
||||
}}
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleClick}
|
||||
|
@ -0,0 +1,12 @@
|
||||
import { ThemeConfig, defaultTheme } from '@nocobase/client';
|
||||
|
||||
// 兼容旧主题
|
||||
function compatOldTheme(theme: ThemeConfig) {
|
||||
if (!theme.token.colorSettings) {
|
||||
theme.token = { ...theme.token, ...defaultTheme.token };
|
||||
}
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
export default compatOldTheme;
|
@ -1,4 +1,4 @@
|
||||
import type { ThemeConfig as Config } from 'antd';
|
||||
import type { ThemeConfig as Config } from '@nocobase/client';
|
||||
import type { ReactElement } from 'react';
|
||||
export type ThemeConfig = Config & { name?: string };
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user