- 设计令牌与组件体系:语义色/间距/圆角/状态 + Card/Metric/Pill/Btn/Field/Empty/Skeleton/Progress 等 - 桌面左侧导航 + 窄屏抽屉(usePathname 高亮、ESC/遮罩关闭);修复抽屉/遮罩占据网格把 main 挤到第二行的问题 - 自绘内联 SVG 图标集替代 emoji;图标/表格/按钮等交互态齐全,空态/加载/错误/禁用态补齐 - 因子研究分层柱状、因子组合与回测净值/回撤双图 + 月度收益热力表、实验页任务状态徽标 - LineChart 主题化并按需引入 echarts(回测/组合首载 JS 448k→281k);next.config 放行局域网 dev 来源
241 lines
6.8 KiB
TypeScript
241 lines
6.8 KiB
TypeScript
/**
|
|
* 内联 SVG 图标集(Phosphor 风格线性图标,1.6px 描边,stroke=currentColor)。
|
|
* 不引入第三方图标库(离线可用),禁止用 emoji 作结构图标。
|
|
*
|
|
* 用法:<Icon name="search" size={16} /> 或 <Icon.Home .../>
|
|
*/
|
|
import type { ReactNode, SVGProps } from "react";
|
|
|
|
export type IconName =
|
|
| "logo"
|
|
| "grid"
|
|
| "candles"
|
|
| "flask"
|
|
| "layers"
|
|
| "gauge"
|
|
| "archive"
|
|
| "search"
|
|
| "x"
|
|
| "chevDown"
|
|
| "chevRight"
|
|
| "arrowUpRight"
|
|
| "arrowUp"
|
|
| "arrowDown"
|
|
| "play"
|
|
| "refresh"
|
|
| "spinner"
|
|
| "alert"
|
|
| "check"
|
|
| "info"
|
|
| "database"
|
|
| "calendar"
|
|
| "target"
|
|
| "chartLine"
|
|
| "scale"
|
|
| "book"
|
|
| "link"
|
|
| "spark"
|
|
| "clock"
|
|
| "filter";
|
|
|
|
const P: Record<
|
|
IconName,
|
|
(p: { filled?: boolean }) => ReactNode
|
|
> = {
|
|
logo: () => (
|
|
<>
|
|
<path d="M4 20V4h4v6h4V4h4v10h4V4h4v16H4z" fill="currentColor" stroke="none" />
|
|
<path d="M3 20h18" strokeWidth="2.4" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
grid: () => (
|
|
<>
|
|
<rect x="3.5" y="3.5" width="7" height="7" rx="1.6" />
|
|
<rect x="13.5" y="3.5" width="7" height="7" rx="1.6" />
|
|
<rect x="3.5" y="13.5" width="7" height="7" rx="1.6" />
|
|
<rect x="13.5" y="13.5" width="7" height="7" rx="1.6" />
|
|
</>
|
|
),
|
|
candles: () => (
|
|
<>
|
|
<path d="M7 3v3.2M7 17.8V21M7 6.2a1.8 1.8 0 0 1 1.8 1.8v6a1.8 1.8 0 0 1-1.8 1.8v0a1.8 1.8 0 0 1-1.8-1.8V8a1.8 1.8 0 0 1 1.8-1.8z" />
|
|
<path d="M17 3v2M17 19v2M17 5a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2v0a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2z" />
|
|
</>
|
|
),
|
|
flask: () => (
|
|
<>
|
|
<path d="M9.5 3h5M10.5 3v6.2L5.2 18.6A2 2 0 0 0 6.9 21.5h10.2a2 2 0 0 0 1.7-2.9L13.5 9.2V3" />
|
|
<path d="M7.2 15.5h9.6" />
|
|
</>
|
|
),
|
|
layers: () => (
|
|
<>
|
|
<path d="M12 3.5 21 8.5l-9 5-9-5 9-5z" />
|
|
<path d="m4.5 12.5 7.5 4.2 7.5-4.2M4.5 16.5l7.5 4.2 7.5-4.2" />
|
|
</>
|
|
),
|
|
gauge: () => (
|
|
<>
|
|
<path d="M12 21a9 9 0 1 1 9-9" />
|
|
<path d="M12 12.5 16.6 6.8" />
|
|
<circle cx="12" cy="12.5" r="1.5" fill="currentColor" stroke="none" />
|
|
</>
|
|
),
|
|
archive: () => (
|
|
<>
|
|
<rect x="3.5" y="4" width="17" height="5" rx="1.6" />
|
|
<path d="M5.5 9v9.5a1.5 1.5 0 0 0 1.5 1.5h10a1.5 1.5 0 0 0 1.5-1.5V9" />
|
|
<path d="M10 13.5h4" />
|
|
</>
|
|
),
|
|
search: () => (
|
|
<>
|
|
<circle cx="11" cy="11" r="6.5" />
|
|
<path d="m20 20-4.4-4.4" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
x: () => (
|
|
<>
|
|
<path d="m6 6 12 12M18 6 6 18" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
chevDown: () => <path d="m6 9.5 6 6 6-6" strokeLinecap="round" strokeLinejoin="round" />,
|
|
chevRight: () => <path d="m9.5 6 6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />,
|
|
arrowUpRight: () => (
|
|
<>
|
|
<path d="M7 17 17 7M9 7h8v8" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
arrowUp: () => <path d="M12 19V5M5.5 11.5 12 5l6.5 6.5" strokeLinecap="round" strokeLinejoin="round" />,
|
|
arrowDown: () => <path d="M12 5v14M18.5 12.5 12 19l-6.5-6.5" strokeLinecap="round" strokeLinejoin="round" />,
|
|
play: ({ filled }) =>
|
|
filled ? (
|
|
<path d="M8 5.5v13a1 1 0 0 0 1.5.9l11-6.5a1 1 0 0 0 0-1.8l-11-6.5A1 1 0 0 0 8 5.5z" fill="currentColor" stroke="none" />
|
|
) : (
|
|
<path d="M8.5 5.8v12.4a.6.6 0 0 0 .9.5l10-6.2a.6.6 0 0 0 0-1L9.4 5.3a.6.6 0 0 0-.9.5z" fill="currentColor" stroke="none" />
|
|
),
|
|
refresh: () => (
|
|
<>
|
|
<path d="M20 12a8 8 0 1 1-2.3-5.6" strokeLinecap="round" />
|
|
<path d="M20 3.5V6.6a.4.4 0 0 1-.4.4H16.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
spinner: () => (
|
|
<>
|
|
<path d="M12 3a9 9 0 1 0 9 9" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
alert: ({ filled }) =>
|
|
filled ? (
|
|
<path
|
|
d="M12 2.6 23 20.8a1 1 0 0 1-.9 1.5H1.9a1 1 0 0 1-.9-1.5L12 2.6zM12 10v4.6m0 3.1v.1"
|
|
fill="currentColor"
|
|
stroke="none"
|
|
opacity="0.25"
|
|
/>
|
|
) : (
|
|
<>
|
|
<path d="M12 3.2 21.7 20a1 1 0 0 1-.85 1.5H3.15A1 1 0 0 1 2.3 20L12 3.2z" />
|
|
<path d="M12 9.5v4.4M12 17.4v.1" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
check: () => <path d="m5 12.5 4.5 4.5L19 7.5" strokeLinecap="round" strokeLinejoin="round" />,
|
|
info: () => (
|
|
<>
|
|
<circle cx="12" cy="12" r="9" />
|
|
<path d="M12 11v5.5M12 7.6v.1" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
database: () => (
|
|
<>
|
|
<ellipse cx="12" cy="5.5" rx="7.5" ry="3" />
|
|
<path d="M4.5 5.5v6c0 1.7 3.4 3 7.5 3s7.5-1.3 7.5-3v-6" />
|
|
<path d="M4.5 11.5v6c0 1.7 3.4 3 7.5 3s7.5-1.3 7.5-3v-6" />
|
|
</>
|
|
),
|
|
calendar: () => (
|
|
<>
|
|
<rect x="3.5" y="5" width="17" height="15.5" rx="2" />
|
|
<path d="M8 3v4M16 3v4M3.5 10h17" />
|
|
</>
|
|
),
|
|
target: () => (
|
|
<>
|
|
<circle cx="12" cy="12" r="8.5" />
|
|
<circle cx="12" cy="12" r="4.5" />
|
|
<circle cx="12" cy="12" r="0.8" fill="currentColor" stroke="none" />
|
|
</>
|
|
),
|
|
chartLine: () => (
|
|
<>
|
|
<path d="M3.5 3.5v17h17" />
|
|
<path d="m6.5 15 4-5 3.5 3 4.5-6.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
scale: () => (
|
|
<>
|
|
<path d="M12 4v16M8 20h8" />
|
|
<path d="m5 8 7-3 7 3-2.2 3H7.2L5 8z" />
|
|
<path d="M3.5 12.2 2 11l3-3M20.5 12.2 22 11l-3-3" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
book: () => (
|
|
<>
|
|
<path d="M4.5 5A2.5 2.5 0 0 1 7 2.5h12V18H7a2.5 2.5 0 0 0-2.5 2.5V5z" />
|
|
<path d="M4.5 20.5A2.5 2.5 0 0 1 7 18h12" />
|
|
<path d="M9.5 7h6" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
link: () => (
|
|
<>
|
|
<path d="M10 14.5 14.5 10" strokeLinecap="round" />
|
|
<path d="M8.2 15.8 5.8 18.2a2.8 2.8 0 1 1-3.9-3.9l4-4a2.8 2.8 0 0 1 3.9 0" strokeLinecap="round" strokeLinejoin="round" />
|
|
<path d="M15.8 8.2l2.4-2.4a2.8 2.8 0 1 1 3.9 3.9l-4 4a2.8 2.8 0 0 1-3.9 0" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
spark: () => (
|
|
<>
|
|
<path d="M12 3.5 13.8 9l5.7 1.4-5.7 1.4L12 17.5l-1.8-5.7L4.5 10.4 10.2 9 12 3.5z" fill="currentColor" stroke="none" opacity="0.35" />
|
|
<path d="M19 15.5l.9 2.6 2.6.9-2.6.9-.9 2.6-.9-2.6-2.6-.9 2.6-.9.9-2.6z" fill="currentColor" stroke="none" />
|
|
</>
|
|
),
|
|
clock: () => (
|
|
<>
|
|
<circle cx="12" cy="12" r="8.5" />
|
|
<path d="M12 7.5V12l3 2" strokeLinecap="round" strokeLinejoin="round" />
|
|
</>
|
|
),
|
|
filter: () => (
|
|
<>
|
|
<path d="M4 6h16M7 12h10M10 18h4" strokeLinecap="round" />
|
|
</>
|
|
),
|
|
};
|
|
|
|
interface IconProps extends Omit<SVGProps<SVGSVGElement>, "name"> {
|
|
name: IconName;
|
|
size?: number;
|
|
/** 填充态(部分图标支持实心强调) */
|
|
filled?: boolean;
|
|
}
|
|
|
|
export function Icon({ name, size = 18, filled = false, ...rest }: IconProps) {
|
|
return (
|
|
<svg
|
|
className="ic"
|
|
width={size}
|
|
height={size}
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
strokeWidth={1.6}
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
aria-hidden="true"
|
|
{...rest}
|
|
>
|
|
{P[name]({ filled })}
|
|
</svg>
|
|
);
|
|
}
|