Files
model-platform/frontend/app/components/common/Icon.tsx
T
2026-08-11 21:26:55 +08:00

198 lines
4.7 KiB
TypeScript

type IconName =
| "brand"
| "home"
| "script"
| "schedule"
| "experiment"
| "database"
| "settings"
| "chevron"
| "search"
| "plus"
| "upload"
| "folder"
| "notebook"
| "python"
| "refresh"
| "close"
| "check"
| "info"
| "lock"
| "unlock"
| "workspace"
| "menu"
| "external"
| "release"
| "play";
type IconProps = {
name: IconName;
size?: number;
strokeWidth?: number;
};
export default function Icon({
name,
size = 18,
strokeWidth = 1.8,
}: IconProps) {
const common = {
width: size,
height: size,
viewBox: "0 0 24 24",
fill: "none",
xmlns: "http://www.w3.org/2000/svg",
"aria-hidden": true,
};
if (name === "brand") {
return (
<svg {...common} viewBox="0 0 32 32">
<path
d="M16 3.5 27 9.8v12.4L16 28.5 5 22.2V9.8L16 3.5Z"
fill="currentColor"
opacity=".2"
/>
<path
d="M16 7.7 23.4 12v8L16 24.3 8.6 20v-8L16 7.7Z"
fill="currentColor"
/>
<circle cx="16" cy="16" r="3.3" fill="white" />
</svg>
);
}
const paths: Record<Exclude<IconName, "brand">, React.ReactNode> = {
home: (
<>
<path d="m3.5 11 8.5-7 8.5 7" />
<path d="M5.5 10v10h13V10M9.5 20v-6h5v6" />
</>
),
script: (
<>
<rect x="5" y="3.5" width="14" height="17" rx="2" />
<path d="M8.5 8h7M8.5 12h7M8.5 16h4.5" />
</>
),
schedule: (
<>
<circle cx="12" cy="12" r="8.5" />
<path d="M12 7.5V12l3.2 2" />
</>
),
experiment: (
<>
<path d="M9 3.5h6M10 3.5v5l-5.2 9a2 2 0 0 0 1.7 3h11a2 2 0 0 0 1.7-3L14 8.5v-5" />
<path d="M7.3 15h9.4" />
</>
),
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" />
</>
),
settings: (
<>
<circle cx="12" cy="12" r="3" />
<path d="M19.4 15a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3 1.7 1.7 0 0 0-1 1.6v.2h-4V21a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9A1.7 1.7 0 0 0 3 14H2.8v-4H3a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1a1.7 1.7 0 0 0 1.9.3A1.7 1.7 0 0 0 10 3v-.2h4V3a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9 1.7 1.7 0 0 0 1.6 1h.2v4H21a1.7 1.7 0 0 0-1.6 1Z" />
</>
),
chevron: <path d="m9 7 5 5-5 5" />,
search: (
<>
<circle cx="10.5" cy="10.5" r="6.5" />
<path d="m15.5 15.5 4 4" />
</>
),
plus: <path d="M12 5v14M5 12h14" />,
upload: (
<>
<path d="M12 16V4m0 0L7.5 8.5M12 4l4.5 4.5" />
<path d="M4 15.5V20h16v-4.5" />
</>
),
folder: (
<path d="M3.5 6.5h6l2 2H20.5v10.5a1.5 1.5 0 0 1-1.5 1.5H5a1.5 1.5 0 0 1-1.5-1.5V6.5Z" />
),
notebook: (
<>
<rect x="5" y="3.5" width="14" height="17" rx="2" />
<path d="M8.5 3.5v17M11.5 8h4M11.5 12h4M11.5 16h2.5" />
</>
),
python: (
<>
<path d="M8 4.5h5.5a2.5 2.5 0 0 1 2.5 2.5v3H8a3 3 0 0 0-3 3v2" />
<path d="M16 19.5h-5.5A2.5 2.5 0 0 1 8 17v-3h8a3 3 0 0 0 3-3V9" />
<circle cx="11" cy="7" r=".8" fill="currentColor" stroke="none" />
<circle cx="13" cy="17" r=".8" fill="currentColor" stroke="none" />
</>
),
refresh: (
<>
<path d="M19 8V4l-1.7 1.7A8 8 0 1 0 20 12" />
<path d="M19 4h-4" />
</>
),
close: <path d="m6 6 12 12M18 6 6 18" />,
check: <path d="m5 12.5 4 4L19 7" />,
info: (
<>
<circle cx="12" cy="12" r="9" />
<path d="M12 11v5M12 8h.01" />
</>
),
lock: (
<>
<rect x="5" y="11" width="14" height="9" rx="2" />
<path d="M8 11V7a4 4 0 0 1 8 0v4" />
</>
),
unlock: (
<>
<rect x="5" y="11" width="14" height="9" rx="2" />
<path d="M8 11V7a4 4 0 0 1 7.5-2" />
</>
),
workspace: (
<>
<rect x="3.5" y="5" width="17" height="14" rx="2" />
<path d="M8 5V3.5h8V5M8 11h8M12 8v6" />
</>
),
menu: (
<>
<path d="M4 6h16M4 12h16M4 18h16" />
</>
),
external: (
<>
<path d="M14 5h5v5M19 5l-8 8" />
<path d="M18 13v6H5V6h6" />
</>
),
release: (
<>
<path d="M12 3.5v11M7.5 8 12 3.5 16.5 8" />
<path d="M5 12.5v7h14v-7" />
</>
),
play: <path d="m8 5 11 7-11 7V5Z" />,
};
return (
<svg
{...common}
stroke="currentColor"
strokeWidth={strokeWidth}
strokeLinecap="round"
strokeLinejoin="round"
>
{paths[name]}
</svg>
);
}