2022-12-27 15:16:14 +08:00
|
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
2022-12-12 11:40:18 +08:00
|
|
|
import { enUS, zhCN, ThemeEditor } from 'antd-token-previewer';
|
2022-12-07 20:22:15 +08:00
|
|
|
import { Button, ConfigProvider, message, Modal, Typography } from 'antd';
|
2022-11-30 11:05:41 +08:00
|
|
|
import type { ThemeConfig } from 'antd/es/config-provider/context';
|
2022-12-07 20:22:15 +08:00
|
|
|
import { Helmet } from 'dumi';
|
|
|
|
import { css } from '@emotion/react';
|
2022-12-27 15:16:14 +08:00
|
|
|
import { EditOutlined } from '@ant-design/icons';
|
|
|
|
import type { JSONContent, TextContent } from 'vanilla-jsoneditor';
|
2022-12-07 20:22:15 +08:00
|
|
|
import useLocale from '../../hooks/useLocale';
|
2022-12-27 15:16:14 +08:00
|
|
|
import JSONEditor from './components/JSONEditor';
|
|
|
|
import { isObject } from './components/utils';
|
2022-12-07 20:22:15 +08:00
|
|
|
|
|
|
|
const locales = {
|
|
|
|
cn: {
|
|
|
|
title: '主题编辑器',
|
|
|
|
save: '保存',
|
|
|
|
reset: '重置',
|
2022-12-27 15:16:14 +08:00
|
|
|
edit: '代码',
|
|
|
|
editModelTitle: '编辑主题配置',
|
|
|
|
editTitle: '在下方编辑你的主题 JSON 即可',
|
|
|
|
editJsonContentTypeError: '主题 JSON 格式错误',
|
|
|
|
editSuccessfully: '编辑成功',
|
2022-12-07 20:22:15 +08:00
|
|
|
saveSuccessfully: '保存成功',
|
|
|
|
},
|
|
|
|
en: {
|
|
|
|
title: 'Theme Editor',
|
|
|
|
save: 'Save',
|
|
|
|
reset: 'Reset',
|
2022-12-27 15:16:14 +08:00
|
|
|
edit: 'Code',
|
|
|
|
editModelTitle: 'edit Theme Config',
|
|
|
|
editTitle: 'Edit your theme JSON below',
|
|
|
|
editJsonContentTypeError: 'The theme of the JSON format is incorrect',
|
|
|
|
editSuccessfully: 'Edited successfully',
|
2022-12-07 20:22:15 +08:00
|
|
|
saveSuccessfully: 'Saved successfully',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const useStyle = () => ({
|
|
|
|
header: css({
|
|
|
|
display: 'flex',
|
|
|
|
height: 56,
|
|
|
|
alignItems: 'center',
|
|
|
|
padding: '0 24px',
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
borderBottom: '1px solid #F0F0F0',
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
|
|
|
const ANT_DESIGN_V5_THEME_EDITOR_THEME = 'ant-design-v5-theme-editor-theme';
|
2022-11-09 12:28:04 +08:00
|
|
|
|
|
|
|
const CustomTheme = () => {
|
2022-12-07 20:22:15 +08:00
|
|
|
const [messageApi, contextHolder] = message.useMessage();
|
|
|
|
const [locale, lang] = useLocale(locales);
|
|
|
|
|
|
|
|
const [theme, setTheme] = React.useState<ThemeConfig>({});
|
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
const [editModelOpen, setEditModelOpen] = useState<boolean>(false);
|
|
|
|
const [editThemeFormatRight, setEditThemeFormatRight] = useState<boolean>(true);
|
|
|
|
const [themeConfigContent, setThemeConfigContent] = useState<JSONContent & TextContent>({
|
|
|
|
text: '{}',
|
|
|
|
json: undefined,
|
|
|
|
});
|
|
|
|
|
2022-12-07 20:22:15 +08:00
|
|
|
useEffect(() => {
|
|
|
|
const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME);
|
|
|
|
if (storedConfig) {
|
|
|
|
setTheme(() => JSON.parse(storedConfig));
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
useEffect(() => {
|
|
|
|
if (editModelOpen === true) return;
|
|
|
|
setThemeConfigContent({
|
|
|
|
json: theme as any,
|
|
|
|
text: undefined,
|
|
|
|
});
|
|
|
|
}, [theme, editModelOpen]);
|
|
|
|
|
2022-12-07 20:22:15 +08:00
|
|
|
const styles = useStyle();
|
|
|
|
|
|
|
|
const handleSave = () => {
|
|
|
|
localStorage.setItem(ANT_DESIGN_V5_THEME_EDITOR_THEME, JSON.stringify(theme));
|
|
|
|
messageApi.success(locale.saveSuccessfully);
|
|
|
|
};
|
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
const handleReset = () => {
|
|
|
|
setTheme({});
|
2022-12-07 20:22:15 +08:00
|
|
|
};
|
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
const handleEditConfig = () => {
|
|
|
|
setEditModelOpen(true);
|
2022-12-07 20:22:15 +08:00
|
|
|
};
|
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
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);
|
|
|
|
}
|
2022-12-07 20:22:15 +08:00
|
|
|
};
|
2022-11-09 12:28:04 +08:00
|
|
|
|
2022-12-27 15:16:14 +08:00
|
|
|
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]);
|
|
|
|
|
2022-11-09 12:28:04 +08:00
|
|
|
return (
|
|
|
|
<div>
|
2022-12-07 20:22:15 +08:00
|
|
|
<Helmet>
|
|
|
|
<title>{`${locale.title} - Ant Design`}</title>
|
|
|
|
<meta property="og:title" content={`${locale.title} - Ant Design`} />
|
|
|
|
</Helmet>
|
|
|
|
{contextHolder}
|
2022-11-22 17:00:28 +08:00
|
|
|
<ConfigProvider theme={{ inherit: false }}>
|
2022-12-07 20:22:15 +08:00
|
|
|
<div css={styles.header}>
|
|
|
|
<Typography.Title level={5} style={{ margin: 0 }}>
|
|
|
|
{locale.title}
|
|
|
|
</Typography.Title>
|
|
|
|
<div>
|
2022-12-27 15:16:14 +08:00
|
|
|
<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 }}>
|
|
|
|
{locale.edit}
|
2022-12-07 20:22:15 +08:00
|
|
|
</Button>
|
|
|
|
<Button onClick={handleReset} style={{ marginRight: 8 }}>
|
|
|
|
{locale.reset}
|
|
|
|
</Button>
|
|
|
|
<Button type="primary" onClick={handleSave}>
|
|
|
|
{locale.save}
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-11-09 12:28:04 +08:00
|
|
|
<ThemeEditor
|
2022-11-22 17:00:28 +08:00
|
|
|
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
|
2022-12-07 20:22:15 +08:00
|
|
|
style={{ height: 'calc(100vh - 64px - 56px)' }}
|
2022-11-19 13:47:33 +08:00
|
|
|
onThemeChange={(newTheme) => {
|
2022-11-09 12:28:04 +08:00
|
|
|
setTheme(newTheme.config);
|
|
|
|
}}
|
2022-12-07 20:22:15 +08:00
|
|
|
locale={lang === 'cn' ? zhCN : enUS}
|
2022-11-09 12:28:04 +08:00
|
|
|
/>
|
|
|
|
</ConfigProvider>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default CustomTheme;
|