Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Theme Config Editor #39621

Merged
merged 4 commits into from Dec 27, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions .dumi/pages/theme-editor/components/JSONEditor.tsx
@@ -0,0 +1,33 @@
import { JSONEditor as Editor, Mode, type JSONEditorPropsOptional } from 'vanilla-jsoneditor';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vanilla-jsoneditor 可以加到 https://ant.design/docs/react/recommendation-cn 里来

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vanilla-jsoneditor 可以加到 https://ant.design/docs/react/recommendation-cn 里来

收到🫡

import React from 'react';

const JSONEditor = (props: JSONEditorPropsOptional) => {
const refContainer = React.useRef(null);
const refEditor = React.useRef(null);

React.useEffect(() => {
refEditor.current = new Editor({
target: refContainer.current,
props: {
mode: Mode.text,
},
});

return () => {
if (refEditor.current) {
refEditor.current.destroy();
refEditor.current = null;
}
};
}, []);

React.useEffect(() => {
if (refEditor.current) {
refEditor.current.updateProps(props);
}
}, [props]);

return <div className="vanilla-jsoneditor-react" ref={refContainer} />;
};

export default JSONEditor;
4 changes: 4 additions & 0 deletions .dumi/pages/theme-editor/components/utils.tsx
@@ -0,0 +1,4 @@
/* eslint-disable import/prefer-default-export */
export function isObject(target: any) {
return Object.prototype.toString.call(target) === '[object Object]';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

这个好像没办法作为 lodash 的平替吧,lodash 还判断了数组什么的

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里我用错了,只想要纯Object,所以这个就够了,不需要_.isObject

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK,那就更不需要 lodash 了,因为 antd 中用到 lodash 的地方不多,所以后面计划把这个库干掉,体积实在太大了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK,那就更不需要 lodash 了,因为 antd 中用到 lodash 的地方不多,所以后面计划把这个库干掉,体积实在太大了

哈哈哈,看到你们的pr了

}
89 changes: 87 additions & 2 deletions .dumi/pages/theme-editor/index.tsx
@@ -1,19 +1,27 @@
import React, { useEffect } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { enUS, zhCN, ThemeEditor } from 'antd-token-previewer';
import { Button, ConfigProvider, message, Modal, Typography } from 'antd';
import type { ThemeConfig } from 'antd/es/config-provider/context';
import { Helmet } from 'dumi';
import { css } from '@emotion/react';
import CopyToClipboard from 'react-copy-to-clipboard';
import { CopyOutlined } from '@ant-design/icons';
import { CopyOutlined, EditOutlined } from '@ant-design/icons';
import type { JSONContent, TextContent } from 'vanilla-jsoneditor';
import useLocale from '../../hooks/useLocale';
import JSONEditor from './components/JSONEditor';
import { isObject } from './components/utils';

const locales = {
cn: {
title: '主题编辑器',
save: '保存',
reset: '重置',
export: '导出',
edit: '编辑',
editModelTitle: '编辑主题配置',
editTitle: '在下方编辑你的主题 JSON 即可',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

将 JSON 复制到 ConfigProvider 的 theme 属性中套用主题。

editJsonContentTypeError: '主题 JSON 格式错误',
editSuccessfully: '编辑成功',
exportDesc: '将下面的 JSON 对象复制到 ConfigProvider 的 theme 属性中即可。',
saveSuccessfully: '保存成功',
},
Expand All @@ -22,6 +30,11 @@ const locales = {
save: 'Save',
reset: 'Reset',
export: 'Export',
edit: 'Edit',
editModelTitle: 'edit Theme Config',
editTitle: 'Edit your theme JSON below',
editJsonContentTypeError: 'The theme of the JSON format is incorrect',
editSuccessfully: 'Edited successfully',
exportDesc: 'Copy the following JSON object to the theme prop of ConfigProvider.',
saveSuccessfully: 'Saved successfully',
},
Expand All @@ -47,13 +60,28 @@ const CustomTheme = () => {

const [theme, setTheme] = React.useState<ThemeConfig>({});

const [editModelOpen, setEditModelOpen] = useState<boolean>(false);
const [editThemeFormatRight, setEditThemeFormatRight] = useState<boolean>(true);
const [themeConfigContent, setThemeConfigContent] = useState<JSONContent & TextContent>({
text: '{}',
json: undefined,
});

useEffect(() => {
const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME);
if (storedConfig) {
setTheme(() => JSON.parse(storedConfig));
}
}, []);

useEffect(() => {
if (editModelOpen === true) return;
setThemeConfigContent({
json: theme as any,
text: undefined,
});
}, [theme, editModelOpen]);

const styles = useStyle();

const handleSave = () => {
Expand Down Expand Up @@ -103,6 +131,43 @@ const CustomTheme = () => {
setTheme({});
};

const handleEditConfig = () => {
setEditModelOpen(true);
};

const editModelClose = useCallback(() => {
setEditModelOpen(false);
}, [themeConfigContent]);

const handleEditConfigChange = (newcontent, preContent, status) => {
setThemeConfigContent(newcontent);
if (
Array.isArray(status.contentErrors.validationErrors) &&
status.contentErrors.validationErrors.length === 0
) {
setEditThemeFormatRight(true);
} else {
setEditThemeFormatRight(false);
}
};

const editSave = useCallback(() => {
if (!editThemeFormatRight) {
message.error(locale.editJsonContentTypeError);
return;
}
const themeConfig = themeConfigContent.text
? JSON.parse(themeConfigContent.text)
: themeConfigContent.json;
if (!isObject(themeConfig)) {
message.error(locale.editJsonContentTypeError);
return;
}
setTheme(themeConfig);
editModelClose();
messageApi.success(locale.editSuccessfully);
}, [themeConfigContent]);

return (
<div>
<Helmet>
Expand All @@ -117,6 +182,26 @@ const CustomTheme = () => {
{locale.title}
</Typography.Title>
<div>
<Modal
open={editModelOpen}
title={locale.editModelTitle}
width={600}
okText={locale.save}
onOk={editSave}
onCancel={editModelClose}
>
<div>
<div style={{ color: 'rgba(0,0,0,0.65)' }}>{locale.editTitle}</div>
<JSONEditor
content={themeConfigContent}
onChange={handleEditConfigChange}
mainMenuBar={false}
/>
</div>
</Modal>
<Button onClick={handleEditConfig} icon={<EditOutlined />} style={{ marginRight: 8 }}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<Button onClick={handleEditConfig} icon={<EditOutlined />} style={{ marginRight: 8 }}>
<Button onClick={handleEditConfig} style={{ marginRight: 8 }}>

{locale.edit}
</Button>
<Button onClick={handleOutput} style={{ marginRight: 8 }}>
{locale.export}
</Button>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -154,7 +154,8 @@
"rc-util": "^5.25.2",
"scroll-into-view-if-needed": "^3.0.3",
"shallowequal": "^1.1.0",
"throttle-debounce": "^5.0.0"
"throttle-debounce": "^5.0.0",
"vanilla-jsoneditor": "^0.11.4"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是不是可以放进 devDependencies 里面?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个是不是可以放进 devDependencies 里面?

应该不可以吧qwq

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该放 devDependencies 里

},
"devDependencies": {
"@ant-design/tools": "^16.1.0-alpha.2",
Expand Down