From 2e1cfb9ced743b4059c682b6ea80593fa6ea4fd1 Mon Sep 17 00:00:00 2001 From: BoyYangZai <2365539910@qq.com> Date: Sun, 18 Dec 2022 03:06:29 +0800 Subject: [PATCH 1/4] feat: add Theme Editor theme upload --- .dumi/pages/theme-editor/index.tsx | 48 ++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/.dumi/pages/theme-editor/index.tsx b/.dumi/pages/theme-editor/index.tsx index bf34cfb4f64e..733fa8eb0412 100644 --- a/.dumi/pages/theme-editor/index.tsx +++ b/.dumi/pages/theme-editor/index.tsx @@ -1,11 +1,12 @@ -import React, { useEffect } from 'react'; +import React, { useCallback, useEffect } from 'react'; import { enUS, zhCN, ThemeEditor } from 'antd-token-previewer'; -import { Button, ConfigProvider, message, Modal, Typography } from 'antd'; +import { Button, ConfigProvider, message, Modal, Typography, Upload, type UploadProps } 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, UploadOutlined } from '@ant-design/icons'; +import isObject from 'lodash/isObject'; import useLocale from '../../hooks/useLocale'; const locales = { @@ -14,6 +15,9 @@ const locales = { save: '保存', reset: '重置', export: '导出', + upload: '上传', + uploadFileTypeError: '只允许上传 JSON 文件', + uploadJsonContentTypeError: 'JSON 文件内容格式错误', exportDesc: '将下面的 JSON 对象复制到 ConfigProvider 的 theme 属性中即可。', saveSuccessfully: '保存成功', }, @@ -22,6 +26,9 @@ const locales = { save: 'Save', reset: 'Reset', export: 'Export', + upload: 'Upload', + uploadFileTypeError: 'Only JSON files can be uploaded', + uploadJsonContentTypeError: 'The content format of the JSON file is incorrect', exportDesc: 'Copy the following JSON object to the theme prop of ConfigProvider.', saveSuccessfully: 'Saved successfully', }, @@ -103,6 +110,36 @@ const CustomTheme = () => { setTheme({}); }; + const uploadJsonThemeFile = useCallback(async (file) => { + if (file.type !== 'application/json') { + message.error({ + content: locale.uploadFileTypeError, + }); + return false; + } + const reader = new FileReader(); + reader.readAsText(file); + reader.onload = () => { + const uploadedThemeConfig = JSON.parse(reader.result as string); + if (!isObject(uploadedThemeConfig)) { + message.error({ + content: locale.uploadJsonContentTypeError, + }); + return; + } + setTheme(uploadedThemeConfig); + }; + }, []); + + const uploadProps: UploadProps = { + name: 'file', + action: '', + showUploadList: false, + beforeUpload: (file) => { + uploadJsonThemeFile(file); + }, + }; + return (
@@ -117,6 +154,11 @@ const CustomTheme = () => { {locale.title}
+ + + From 5202c9733f57ee5abfb485772094b98d855aafbd Mon Sep 17 00:00:00 2001 From: BoyYangZai <2365539910@qq.com> Date: Sun, 18 Dec 2022 20:45:01 +0800 Subject: [PATCH 2/4] verision 2 --- .../theme-editor/components/JSONEditor.tsx | 33 +++++ .dumi/pages/theme-editor/index.tsx | 116 +++++++++++------- package.json | 3 +- 3 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 .dumi/pages/theme-editor/components/JSONEditor.tsx diff --git a/.dumi/pages/theme-editor/components/JSONEditor.tsx b/.dumi/pages/theme-editor/components/JSONEditor.tsx new file mode 100644 index 000000000000..28a71ee33b0e --- /dev/null +++ b/.dumi/pages/theme-editor/components/JSONEditor.tsx @@ -0,0 +1,33 @@ +import { JSONEditor as Editor, Mode, type JSONEditorPropsOptional } from 'vanilla-jsoneditor'; +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
; +}; + +export default JSONEditor; diff --git a/.dumi/pages/theme-editor/index.tsx b/.dumi/pages/theme-editor/index.tsx index 733fa8eb0412..5bb92e15c3f4 100644 --- a/.dumi/pages/theme-editor/index.tsx +++ b/.dumi/pages/theme-editor/index.tsx @@ -1,13 +1,15 @@ -import React, { useCallback, useEffect } from 'react'; +import { isObject } from 'lodash'; +import React, { useCallback, useEffect, useState } from 'react'; import { enUS, zhCN, ThemeEditor } from 'antd-token-previewer'; -import { Button, ConfigProvider, message, Modal, Typography, Upload, type UploadProps } from 'antd'; +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, UploadOutlined } from '@ant-design/icons'; -import isObject from 'lodash/isObject'; +import { CopyOutlined, EditOutlined } from '@ant-design/icons'; +import { type TextContent } from 'vanilla-jsoneditor'; import useLocale from '../../hooks/useLocale'; +import JSONEditor from './components/JSONEditor'; const locales = { cn: { @@ -15,9 +17,11 @@ const locales = { save: '保存', reset: '重置', export: '导出', - upload: '上传', - uploadFileTypeError: '只允许上传 JSON 文件', - uploadJsonContentTypeError: 'JSON 文件内容格式错误', + edit: '编辑', + editModelTitle: '编辑主题配置', + editTitle: '在下方编辑你的主题 JSON 即可', + editJsonContentTypeError: '主题 JSON 格式错误', + editSuccessfully: '编辑成功', exportDesc: '将下面的 JSON 对象复制到 ConfigProvider 的 theme 属性中即可。', saveSuccessfully: '保存成功', }, @@ -26,9 +30,11 @@ const locales = { save: 'Save', reset: 'Reset', export: 'Export', - upload: 'Upload', - uploadFileTypeError: 'Only JSON files can be uploaded', - uploadJsonContentTypeError: 'The content format of the JSON file is incorrect', + 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', }, @@ -110,36 +116,47 @@ const CustomTheme = () => { setTheme({}); }; - const uploadJsonThemeFile = useCallback(async (file) => { - if (file.type !== 'application/json') { - message.error({ - content: locale.uploadFileTypeError, - }); - return false; - } - const reader = new FileReader(); - reader.readAsText(file); - reader.onload = () => { - const uploadedThemeConfig = JSON.parse(reader.result as string); - if (!isObject(uploadedThemeConfig)) { - message.error({ - content: locale.uploadJsonContentTypeError, - }); - return; - } - setTheme(uploadedThemeConfig); - }; - }, []); + const [editModelOpen, setEditModelOpen] = useState(false); + const [editThemeFormatRight, setEditThemeFormatRight] = useState(true); + const [content, setContent] = useState({ + text: '{}', + }); - const uploadProps: UploadProps = { - name: 'file', - action: '', - showUploadList: false, - beforeUpload: (file) => { - uploadJsonThemeFile(file); - }, + const handleEditConfig = () => { + setEditModelOpen(true); }; + const editModelClose = useCallback(() => { + setEditModelOpen(false); + }, [content]); + + const handleEditConfigChange = (newcontent, preContent, status) => { + setContent(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 = JSON.parse(content.text); + if (!isObject(themeConfig)) { + message.error(locale.editJsonContentTypeError); + return; + } + setTheme(themeConfig); + editModelClose(); + messageApi.success(locale.editSuccessfully); + }, [content]); + return (
@@ -154,11 +171,26 @@ const CustomTheme = () => { {locale.title}
- - - + +
+
{locale.editTitle}
+ +
+
+ diff --git a/package.json b/package.json index 6dcc816c1f49..5894a91c95dc 100644 --- a/package.json +++ b/package.json @@ -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" }, "devDependencies": { "@ant-design/tools": "^16.1.0-alpha.2", From 344f6c506bddf02ceeec23de55aa0251750e4c1b Mon Sep 17 00:00:00 2001 From: BoyYangZai <2365539910@qq.com> Date: Mon, 19 Dec 2022 01:02:33 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E7=A7=BB=E9=99=A4lodash=E3=80=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=BD=93=E5=89=8DConfig?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dumi/pages/theme-editor/components/utils.tsx | 4 ++ .dumi/pages/theme-editor/index.tsx | 37 ++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) create mode 100644 .dumi/pages/theme-editor/components/utils.tsx diff --git a/.dumi/pages/theme-editor/components/utils.tsx b/.dumi/pages/theme-editor/components/utils.tsx new file mode 100644 index 000000000000..afc5450e5fbd --- /dev/null +++ b/.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]'; +} diff --git a/.dumi/pages/theme-editor/index.tsx b/.dumi/pages/theme-editor/index.tsx index 5bb92e15c3f4..f071fc7daa44 100644 --- a/.dumi/pages/theme-editor/index.tsx +++ b/.dumi/pages/theme-editor/index.tsx @@ -1,4 +1,3 @@ -import { isObject } from 'lodash'; import React, { useCallback, useEffect, useState } from 'react'; import { enUS, zhCN, ThemeEditor } from 'antd-token-previewer'; import { Button, ConfigProvider, message, Modal, Typography } from 'antd'; @@ -7,9 +6,10 @@ import { Helmet } from 'dumi'; import { css } from '@emotion/react'; import CopyToClipboard from 'react-copy-to-clipboard'; import { CopyOutlined, EditOutlined } from '@ant-design/icons'; -import { type TextContent } from 'vanilla-jsoneditor'; +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: { @@ -60,6 +60,13 @@ const CustomTheme = () => { const [theme, setTheme] = React.useState({}); + const [editModelOpen, setEditModelOpen] = useState(false); + const [editThemeFormatRight, setEditThemeFormatRight] = useState(true); + const [themeConfigContent, setThemeConfigContent] = useState({ + text: '{}', + json: undefined, + }); + useEffect(() => { const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME); if (storedConfig) { @@ -67,6 +74,14 @@ const CustomTheme = () => { } }, []); + useEffect(() => { + if (editModelOpen === true) return; + setThemeConfigContent({ + json: theme as any, + text: undefined, + }); + }, [theme, editModelOpen]); + const styles = useStyle(); const handleSave = () => { @@ -116,22 +131,16 @@ const CustomTheme = () => { setTheme({}); }; - const [editModelOpen, setEditModelOpen] = useState(false); - const [editThemeFormatRight, setEditThemeFormatRight] = useState(true); - const [content, setContent] = useState({ - text: '{}', - }); - const handleEditConfig = () => { setEditModelOpen(true); }; const editModelClose = useCallback(() => { setEditModelOpen(false); - }, [content]); + }, [themeConfigContent]); const handleEditConfigChange = (newcontent, preContent, status) => { - setContent(newcontent); + setThemeConfigContent(newcontent); if ( Array.isArray(status.contentErrors.validationErrors) && status.contentErrors.validationErrors.length === 0 @@ -147,7 +156,9 @@ const CustomTheme = () => { message.error(locale.editJsonContentTypeError); return; } - const themeConfig = JSON.parse(content.text); + const themeConfig = themeConfigContent.text + ? JSON.parse(themeConfigContent.text) + : themeConfigContent.json; if (!isObject(themeConfig)) { message.error(locale.editJsonContentTypeError); return; @@ -155,7 +166,7 @@ const CustomTheme = () => { setTheme(themeConfig); editModelClose(); messageApi.success(locale.editSuccessfully); - }, [content]); + }, [themeConfigContent]); return (
@@ -182,7 +193,7 @@ const CustomTheme = () => {
{locale.editTitle}
From bb2cfc0acc5bc26561da3a9958a296692754e734 Mon Sep 17 00:00:00 2001 From: BoyYangZai <2365539910@qq.com> Date: Mon, 19 Dec 2022 14:55:59 +0800 Subject: [PATCH 4/4] remove export,add into devDependencies,add tool link --- .dumi/pages/theme-editor/index.tsx | 54 ++---------------------------- docs/react/recommendation.zh-CN.md | 1 + package.json | 4 +-- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/.dumi/pages/theme-editor/index.tsx b/.dumi/pages/theme-editor/index.tsx index f071fc7daa44..c651513a5547 100644 --- a/.dumi/pages/theme-editor/index.tsx +++ b/.dumi/pages/theme-editor/index.tsx @@ -4,8 +4,7 @@ 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, EditOutlined } from '@ant-design/icons'; +import { EditOutlined } from '@ant-design/icons'; import type { JSONContent, TextContent } from 'vanilla-jsoneditor'; import useLocale from '../../hooks/useLocale'; import JSONEditor from './components/JSONEditor'; @@ -16,26 +15,22 @@ const locales = { title: '主题编辑器', save: '保存', reset: '重置', - export: '导出', - edit: '编辑', + edit: '代码', editModelTitle: '编辑主题配置', editTitle: '在下方编辑你的主题 JSON 即可', editJsonContentTypeError: '主题 JSON 格式错误', editSuccessfully: '编辑成功', - exportDesc: '将下面的 JSON 对象复制到 ConfigProvider 的 theme 属性中即可。', saveSuccessfully: '保存成功', }, en: { title: 'Theme Editor', save: 'Save', reset: 'Reset', - export: 'Export', - edit: 'Edit', + edit: 'Code', 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', }, }; @@ -55,7 +50,6 @@ const ANT_DESIGN_V5_THEME_EDITOR_THEME = 'ant-design-v5-theme-editor-theme'; const CustomTheme = () => { const [messageApi, contextHolder] = message.useMessage(); - const [modalApi, modalContextHolder] = Modal.useModal(); const [locale, lang] = useLocale(locales); const [theme, setTheme] = React.useState({}); @@ -89,44 +83,6 @@ const CustomTheme = () => { messageApi.success(locale.saveSuccessfully); }; - const onCopy = (text: string, result: boolean) => { - if (result) { - messageApi.success('Copy theme config successfully!'); - } else { - messageApi.error('Copy failed, please try again.'); - } - }; - - const handleOutput = () => { - modalApi.info({ - title: locale.export, - width: 600, - content: ( -
-
{locale.exportDesc}
-
-            
-              
-
- ), - }); - }; - const handleReset = () => { setTheme({}); }; @@ -175,7 +131,6 @@ const CustomTheme = () => { {contextHolder} - {modalContextHolder}
@@ -202,9 +157,6 @@ const CustomTheme = () => { - diff --git a/docs/react/recommendation.zh-CN.md b/docs/react/recommendation.zh-CN.md index 835c57fabbbf..3a53d8db8f02 100644 --- a/docs/react/recommendation.zh-CN.md +++ b/docs/react/recommendation.zh-CN.md @@ -15,6 +15,7 @@ title: 社区精选组件 | 拖拽 | [dnd-kit](https://github.com/clauderic/dnd-kit) [react-beautiful-dnd](https://github.com/atlassian/react-beautiful-dnd/) [react-dnd](https://github.com/gaearon/react-dnd) [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc) | | 代码编辑器 | [react-codemirror2](https://github.com/scniro/react-codemirror2) [react-monaco-editor](https://github.com/superRaytin/react-monaco-editor) | | 富文本编辑器 | [react-quill](https://github.com/zenoamaro/react-quill) [braft-editor](https://github.com/margox/braft-editor) | +| JSON 编辑器 | [vanilla-jsoneditor](https://github.com/josdejong/svelte-jsoneditor) | | JSON 显示器 | [react-json-view](https://github.com/mac-s-g/react-json-view) | | 拾色器 | [react-colorful](https://github.com/omgovich/react-colorful) [react-color](http://casesandberg.github.io/react-color/) | | 响应式 | [react-responsive](https://github.com/contra/react-responsive) [react-media](https://github.com/ReactTraining/react-media) | diff --git a/package.json b/package.json index 5894a91c95dc..022a8c767302 100644 --- a/package.json +++ b/package.json @@ -154,8 +154,7 @@ "rc-util": "^5.25.2", "scroll-into-view-if-needed": "^3.0.3", "shallowequal": "^1.1.0", - "throttle-debounce": "^5.0.0", - "vanilla-jsoneditor": "^0.11.4" + "throttle-debounce": "^5.0.0" }, "devDependencies": { "@ant-design/tools": "^16.1.0-alpha.2", @@ -285,6 +284,7 @@ "ts-node": "^10.8.2", "typedoc": "^0.23.21", "typescript": "~4.9.3", + "vanilla-jsoneditor": "^0.11.4", "webpack-bundle-analyzer": "^4.1.0", "xhr-mock": "^2.4.1", "yaml-front-matter": "^4.0.0"