mirror of
https://github.com/ant-design/ant-design.git
synced 2024-12-25 00:08:27 +08:00
59ad48476b
* chore: add boime lint * fix lint * use files ignore * revert change * ignore clarity.js * fix some errors * fix some errors * fix some errors * fix some errors * add yml file * Update clarity.js Signed-off-by: afc163 <afc163@gmail.com> * add npm run lint:biome * add npm run lint:biome * fix test case * fix ts errors * fix ts errors * fix lint and add .lintstagedrc * shorten prop name * chore: update package.json * update biome.json * chore: remove stylelint * chore: useOptionalChain * fix lint * biome format * prettier all code * prettier all code * fix site test --------- Signed-off-by: afc163 <afc163@gmail.com>
108 lines
3.0 KiB
TypeScript
108 lines
3.0 KiB
TypeScript
import type { FC } from 'react';
|
||
import React, { useRef } from 'react';
|
||
import { CheckOutlined, SketchOutlined } from '@ant-design/icons';
|
||
import { App } from 'antd';
|
||
import { createStyles } from 'antd-style';
|
||
import copy from 'copy-to-clipboard';
|
||
import { nodeToGroup } from 'html2sketch';
|
||
|
||
import type { AntdPreviewerProps } from './Previewer';
|
||
|
||
const useStyle = createStyles(({ token, css }) => ({
|
||
wrapper: css`
|
||
position: relative;
|
||
border: 1px solid ${token.colorBorderSecondary};
|
||
border-radius: ${token.borderRadius}px;
|
||
padding: ${token.paddingMD}px ${token.paddingLG}px ${token.paddingMD * 2}px;
|
||
margin-bottom: ${token.marginLG}px;
|
||
`,
|
||
title: css`
|
||
font-size: ${token.fontSizeLG}px;
|
||
font-weight: ${token.fontWeightStrong};
|
||
color: ${token.colorTextHeading};
|
||
|
||
&:hover {
|
||
color: ${token.colorTextHeading};
|
||
}
|
||
`,
|
||
description: css`
|
||
margin-top: ${token.margin}px;
|
||
`,
|
||
demo: css`
|
||
margin-top: ${token.marginLG}px;
|
||
display: flex;
|
||
justify-content: center;
|
||
`,
|
||
copy: css`
|
||
position: absolute;
|
||
inset-inline-end: ${token.paddingMD}px;
|
||
inset-block-start: ${token.paddingMD}px;
|
||
cursor: pointer;
|
||
`,
|
||
copyTip: css`
|
||
color: ${token.colorTextTertiary};
|
||
`,
|
||
copiedTip: css`
|
||
.anticon {
|
||
color: ${token.colorSuccess};
|
||
}
|
||
`,
|
||
tip: css`
|
||
color: ${token.colorTextTertiary};
|
||
margin-top: ${token.marginMD * 2}px;
|
||
`,
|
||
}));
|
||
|
||
const DesignPreviewer: FC<AntdPreviewerProps> = ({ children, title, description, tip, asset }) => {
|
||
const { styles } = useStyle();
|
||
const demoRef = useRef<HTMLDivElement>(null);
|
||
const [copied, setCopied] = React.useState<boolean>(false);
|
||
const { message } = App.useApp();
|
||
|
||
const handleCopy = async () => {
|
||
try {
|
||
if (demoRef.current) {
|
||
const group = await nodeToGroup(demoRef.current);
|
||
copy(JSON.stringify(group.toSketchJSON()));
|
||
setCopied(true);
|
||
setTimeout(() => {
|
||
setCopied(false);
|
||
}, 5000);
|
||
}
|
||
} catch {
|
||
message.error('复制失败');
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className={styles.wrapper} id={asset.id}>
|
||
<a className={styles.title} href={`#${asset.id}`}>
|
||
{title}
|
||
</a>
|
||
{description && (
|
||
// biome-ignore lint/security/noDangerouslySetInnerHtml: description is from markdown
|
||
<div className={styles.description} dangerouslySetInnerHTML={{ __html: description }} />
|
||
)}
|
||
<div className={styles.copy}>
|
||
{copied ? (
|
||
<div className={styles.copiedTip}>
|
||
<CheckOutlined />
|
||
<span style={{ marginInlineStart: 8 }}>已复制,使用 Kitchen 插件即可粘贴</span>
|
||
</div>
|
||
) : (
|
||
<button type="button" onClick={handleCopy} className={styles.copyTip}>
|
||
<SketchOutlined />
|
||
<span style={{ marginInlineStart: 8 }}>复制 Sketch JSON</span>
|
||
</button>
|
||
)}
|
||
</div>
|
||
<div className={styles.demo} ref={demoRef}>
|
||
{children}
|
||
</div>
|
||
<div className={styles.tip}>{tip}</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default DesignPreviewer;
|