Last active
March 3, 2026 06:42
-
-
Save Wxh16144/48cf1f67a40530c73375449d8a6b1b2b to your computer and use it in GitHub Desktop.
可视化 Ant Design Token
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

ScreenShot