docs: bump theme-editor (#44171)

* chore: fix plugin antd import

* chore: code clean

* chore: fix image test

* chore: fix image test
This commit is contained in:
MadCcc 2023-08-11 19:37:53 +08:00 committed by GitHub
parent 8368458bf7
commit ddfe37a14e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 42 additions and 131 deletions

View File

@ -1,17 +1,11 @@
import { createStyles } from 'antd-style';
import { ThemeEditor, enUS, zhCN } from 'antd-token-previewer';
import { enUS, zhCN } from 'antd-token-previewer';
import { Helmet } from 'dumi';
import React, { Suspense, useCallback, useEffect, useState } from 'react';
import type { JSONContent, TextContent } from 'vanilla-jsoneditor';
import React, { Suspense, useEffect } from 'react';
import type { ThemeConfig } from 'antd/es/config-provider/context';
import { Button, ConfigProvider, Modal, Spin, Typography, message } from 'antd';
import { Button, message, Skeleton } from 'antd';
import useLocale from '../../hooks/useLocale';
const JSONEditor = React.lazy(() => import('../../theme/common/JSONEditor'));
function isObject(target: any) {
return Object.prototype.toString.call(target) === '[object Object]';
}
const ThemeEditor = React.lazy(() => import('antd-token-previewer/lib/ThemeEditor'));
const locales = {
cn: {
@ -38,17 +32,6 @@ const locales = {
},
};
const useStyle = createStyles(({ css }) => ({
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';
const CustomTheme = () => {
@ -57,13 +40,6 @@ 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) {
@ -77,61 +53,11 @@ const CustomTheme = () => {
}
}, []);
const { styles } = useStyle();
const handleSave = () => {
localStorage.setItem(ANT_DESIGN_V5_THEME_EDITOR_THEME, JSON.stringify(theme));
messageApi.success(locale.saveSuccessfully);
};
const handleEditConfig = () => {
setEditModelOpen(true);
};
const editModelClose = useCallback(() => {
setEditModelOpen(false);
}, [themeConfigContent]);
const handleEditConfigChange = (newcontent, preContent, status) => {
setThemeConfigContent(newcontent);
setEditThemeFormatRight(!status.contentErrors);
};
const editSave = useCallback(() => {
const contentFormatError = !editThemeFormatRight;
if (contentFormatError) {
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, editThemeFormatRight]);
const handleExport = () => {
const file = new File([JSON.stringify(theme, null, 2)], `Ant Design Theme.json`, {
type: 'text/json; charset=utf-8;',
});
const tmpLink = document.createElement('a');
const objectUrl = URL.createObjectURL(file);
tmpLink.href = objectUrl;
tmpLink.download = file.name;
document.body.appendChild(tmpLink);
tmpLink.click();
document.body.removeChild(tmpLink);
URL.revokeObjectURL(objectUrl);
};
return (
<div>
<Helmet>
@ -139,58 +65,22 @@ const CustomTheme = () => {
<meta property="og:title" content={`${locale.title} - Ant Design`} />
</Helmet>
{contextHolder}
<ConfigProvider theme={{ inherit: false }}>
<div className={styles.header}>
<Typography.Title level={5} style={{ margin: 0 }}>
{locale.title}
</Typography.Title>
<div>
<Modal
open={editModelOpen}
title={locale.editModelTitle}
width={600}
okText={locale.save}
onOk={editSave}
onCancel={editModelClose}
>
<Suspense
fallback={
<div style={{ textAlign: 'center', width: '100%', padding: '24px 0' }}>
<Spin tip={locale.initialEditor} />
</div>
}
>
<JSONEditor
content={themeConfigContent}
onChange={handleEditConfigChange}
mainMenuBar={false}
/>
</Suspense>
</Modal>
<Button onClick={handleExport} style={{ marginRight: 8 }}>
{locale.export}
</Button>
<Button onClick={handleEditConfig} style={{ marginRight: 8 }}>
{locale.edit}
</Button>
<Suspense fallback={<Skeleton style={{ margin: 24 }} />}>
<ThemeEditor
advanced
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
style={{ height: 'calc(100vh - 64px)' }}
onThemeChange={(newTheme) => {
setTheme(newTheme.config);
}}
locale={lang === 'cn' ? zhCN : enUS}
actions={
<Button type="primary" onClick={handleSave}>
{locale.save}
</Button>
</div>
</div>
<ThemeEditor
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
style={{ height: 'calc(100vh - 64px - 56px)' }}
onThemeChange={(newTheme) => {
setTheme(newTheme.config);
setThemeConfigContent({
json: newTheme.config,
text: undefined,
});
}}
locale={lang === 'cn' ? zhCN : enUS}
}
/>
</ConfigProvider>
</Suspense>
</div>
);
};

View File

@ -5,9 +5,28 @@ import type { IApi, IRoute } from 'dumi';
import ReactTechStack from 'dumi/dist/techStacks/react';
import chalk from 'chalk';
import sylvanas from 'sylvanas';
import { extractStaticStyle } from 'antd-style';
import createEmotionServer from '@emotion/server/create-instance';
import localPackage from '../../package.json';
function extractEmotionStyle(html: string) {
// copy from emotion ssr
// https://github.com/vercel/next.js/blob/deprecated-main/examples/with-emotion-vanilla/pages/_document.js
const styles = global.__ANTD_STYLE_CACHE_MANAGER_FOR_SSR__.getCacheList().map((cache) => {
const result = createEmotionServer(cache).extractCritical(html);
if (!result.css) return null;
const { css, ids } = result;
return {
key: cache.key,
css,
ids,
tag: `<style data-emotion="${cache.key} ${result.ids.join(' ')}">${result.css}</style>`,
};
});
return styles.filter(Boolean);
}
export const getHash = (str: string, length = 8) =>
createHash('md5').update(str).digest('hex').slice(0, length);
@ -129,7 +148,7 @@ const RoutesPlugin = (api: IApi) => {
file.content = file.content.replace('</head>', `${globalStyles}</head>`);
// 1. 提取 antd-style 样式
const styles = extractStaticStyle(file.content, { includeAntd: false });
const styles = extractEmotionStyle(file.content);
// 2. 提取每个样式到独立 css 文件
styles.forEach((result) => {

View File

@ -11,6 +11,7 @@ export default defineConfig({
},
ssr: process.env.NODE_ENV === 'production' ? {} : false,
hash: true,
mfsu: false,
crossorigin: {},
outputPath: '_site',
favicons: ['https://gw.alipayobjects.com/zos/rmsportal/rlpTLlbMzTNYuZGGCVYM.png'],
@ -34,7 +35,6 @@ export default defineConfig({
},
extraRehypePlugins: [rehypeAntd],
extraRemarkPlugins: [remarkAntd],
mfsu: false,
metas: [{ name: 'theme-color', content: '#1677ff' }],
analytics: {
ga_v2: 'UA-72788897-1',

View File

@ -33,6 +33,8 @@ module.exports = {
'/\\.(css|less)$/': 'identity-obj-proxy',
'^antd$': '<rootDir>/components/index',
'^antd/es/(.*)$': '<rootDir>/components/$1',
'^antd/lib/(.*)$': '<rootDir>/components/$1',
'^antd/locale/(.*)$': '<rootDir>/components/locale/$1',
},
testPathIgnorePatterns: ['/node_modules/', 'dekko', 'node', 'image.test.js', 'image.test.ts'],
transform: {

View File

@ -210,7 +210,7 @@
"@typescript-eslint/parser": "^5.40.0",
"antd-img-crop": "^4.9.0",
"antd-style": "^3.4.2-beta.1",
"antd-token-previewer": "^1.1.0-21",
"antd-token-previewer": "^2.0.1",
"chalk": "^4.0.0",
"cheerio": "1.0.0-rc.12",
"circular-dependency-plugin": "^5.2.2",

View File

@ -38,7 +38,7 @@ export default function imageTest(component: React.ReactElement) {
MockDate.set(dayjs('2016-11-22').valueOf());
page.on('request', onRequestHandle);
await page.goto(`file://${process.cwd()}/tests/index.html`);
await page.addStyleTag({ path: `${process.cwd()}/dist/reset.css` });
await page.addStyleTag({ path: `${process.cwd()}/components/style/reset.css` });
await page.addStyleTag({ content: '*{animation: none!important;}' });
const cache = createCache();