Skip to content

Instantly share code, notes, and snippets.

@Wxh16144
Last active March 3, 2026 06:42
Show Gist options
  • Select an option

  • Save Wxh16144/48cf1f67a40530c73375449d8a6b1b2b to your computer and use it in GitHub Desktop.

Select an option

Save Wxh16144/48cf1f67a40530c73375449d8a6b1b2b to your computer and use it in GitHub Desktop.
可视化 Ant Design Token
import { Typography, List, theme, Slider, Space, InputNumber, message } from "antd";
import { FastColor } from "@ant-design/fast-color";
import { createGlobalStyle, ThemeProvider, type ThemeMode, createStyles } from "antd-style";
import { NuqsAdapter } from "nuqs/adapters/react";
import type { PropsWithChildren } from "react";
import { parseAsStringEnum, useQueryState, parseAsInteger } from "nuqs";
export const setupInstructions = `
# Create a new directory for your project
mkdir hi-antd-token && cd hi-antd-token
# Create a new React project
npm create vite@latest . --template react-ts
# Install dependencies
npm install antd antd-style @ant-design/fast-color nuqs
`;
const useStyles = createStyles(({ token, css }, { size, color }: { size: number; color?: string }) => {
return {
// Demo 容器样式
container: css`
padding: 24px;
`,
controls: css`
margin-bottom: 24px;
`,
// 列表项样式
itemWrapper: css`
display: flex;
flex-direction: column;
align-items: center;
`,
textLabel: css`
max-width: 100%;
font-size: 12px;
`,
textValue: css`
font-size: 10px;
`,
// ColorBlock 样式
block: css`
width: ${size}px;
height: ${size}px;
background-color: ${color};
border-radius: ${token.borderRadiusLG}px;
border: 1px solid ${token.colorBorderSecondary};
margin-bottom: 8px;
transition: all 0.2s;
position: relative;
overflow: hidden;
`,
triangle: css`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
z-index: 1;
transition: background-color 0.2s;
`,
topTriangle: css`
clip-path: polygon(0 0, 100% 0, 0 100%);
&:hover {
background-color: rgba(255, 255, 255, 0.3);
}
`,
bottomTriangle: css`
clip-path: polygon(100% 0, 100% 100%, 0 100%);
&:hover {
background-color: rgba(0, 0, 0, 0.2);
}
`,
};
});
const ColorBlock = ({
value,
name,
size,
}: {
value: string;
name: string;
size: number;
}) => {
const { styles, cx } = useStyles({ size, color: value });
const handleCopy = (text: string, type: string) => {
navigator.clipboard.writeText(text);
message.success(`Copied ${type}: ${text}`);
};
return (
<div className={styles.block}>
{/* 左上角三角形:复制 Token */}
<div
title={`Click to copy token: token.${name}`}
className={cx(styles.triangle, styles.topTriangle)}
onClick={() => handleCopy(`token.${name}`, "Token")}
/>
{/* 右下角三角形:复制 Hex 值 */}
<div
title={`Click to copy value: ${value}`}
className={cx(styles.triangle, styles.bottomTriangle)}
onClick={() => handleCopy(value, "Value")}
/>
</div>
);
};
const Demo = () => {
const { token } = theme.useToken();
const [size, setSize] = useQueryState("size", parseAsInteger.withDefault(64));
const { styles } = useStyles({ size });
const color = {
// text: token.colorText,
// background: token.colorBgContainer,
// error: token.colorError,
// primary: token.colorPrimary,
// success: token.colorSuccess,
// warning: token.colorWarning,
// info: token.colorInfo,
// link: token.colorLink,
// border: token.colorBorder,
// borderSecondary: token.colorBorderSecondary,
...Object.entries(token).reduce((acc, [key, value]) => {
if (key.startsWith("color")) {
acc[key] = value;
}
return acc;
}, {} as Record<string, string>),
} as const;
const hexColor = Object.entries(color).reduce((acc, [key, value]) => {
acc[key] = new FastColor(value).toHexString();
return acc;
}, {} as Record<string, string>);
return (
<div className={styles.container}>
<Space className={styles.controls}>
<Typography.Text strong>Block Size:</Typography.Text>
<Slider
min={24}
max={160}
style={{ width: 160 }}
value={size}
onChange={setSize}
/>
<InputNumber
min={24}
max={160}
value={size}
onChange={(val) => val && setSize(val)}
/>
</Space>
<List
grid={{ gutter: 16, xs: 2, sm: 3, md: 4, lg: 6, xl: 8, xxl: 10 }}
dataSource={Object.entries(hexColor)}
renderItem={([key, value]) => (
<List.Item>
<div className={styles.itemWrapper}>
<ColorBlock
value={value}
name={key}
size={size}
/>
<Typography.Text
ellipsis
className={styles.textLabel}
title={key}
>
{key}
</Typography.Text>
<Typography.Text type="secondary" className={styles.textValue}>
{value}
</Typography.Text>
</div>
</List.Item>
)}
/>
</div>
);
};
const GlobalStyle = createGlobalStyle`
body {
color: ${({ theme }) => theme.colorBgBase};
background-color: ${({ theme }) => theme.colorBgContainer};
}
`;
const Theme = ({ children }: PropsWithChildren) => {
const [themeMode] = useQueryState<ThemeMode>(
"theme",
parseAsStringEnum(["auto", "light", "dark"])
.withDefault("auto")
.withOptions({
clearOnDefault: true,
})
);
return (
<ThemeProvider themeMode={themeMode}>
<GlobalStyle />
{children}
</ThemeProvider>
);
};
const App = () => {
return (
<NuqsAdapter>
<Theme>
<Demo />
</Theme>
</NuqsAdapter>
);
};
export default App;
@Wxh16144
Copy link
Author

ScreenShot

image

@Wxh16144
Copy link
Author

Wxh16144 commented Mar 3, 2026

ScreenShot(V2)

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment