Files
opsxapi/packages/ui/src/components/EnvBadge.tsx
T
logan dec66db5aa feat: OpsxAPI v1.0 全协议接口工作台
- 六协议调试:HTTP/GraphQL/WebSocket/SSE/Socket.IO/MQTT
- 集合树/多标签/多环境变量/历史记录,localStorage 持久化
- 导入:OpenAPI 2/3/3.1、Postman、Apifox、Apipost、cURL、HAR、
  Insomnia、Hoppscotch、Markdown(自动识别,21 个单测覆盖)
- 导出:OpenAPI 3.0 JSON/YAML、Postman v2.1、Markdown 文档、
  全量备份;单请求生成 cURL/fetch/Python/Go 代码
- Gin 服务:HTTP 代理、NDJSON 流式代理(SSE 透传)、
  WebSocket 隧道(浏览器自定义握手 Header)
- 内置产品官网 /home 与用户文档站 /docs(SSR,随二进制交付)
- lucide 图标体系 + 品牌标识(Logo/favicon),明暗双主题
- 环境变量:彩色徽标切换器、管理弹窗、{{ 自动补全
2026-09-18 00:16:59 +08:00

62 lines
1.4 KiB
TypeScript

/**
* 环境徽标:取环境名首字的彩色单字标(颜色按 id 稳定分配)。
* 左栏列表、顶栏切换器、环境弹窗共用,帮助一眼识别当前环境。
*/
import type { CSSProperties } from "react";
const PALETTE = [
"#3b82f6", // blue
"#8b5cf6", // violet
"#10b981", // emerald
"#f59e0b", // amber
"#f43f5e", // rose
"#06b6d4", // cyan
"#ec4899", // pink
"#84cc16", // lime
];
function hashColor(id: string): string {
let h = 0;
for (let i = 0; i < id.length; i++) h = (h * 31 + id.charCodeAt(i)) >>> 0;
return PALETTE[h % PALETTE.length];
}
function firstChar(name: string): string {
const trimmed = (name || "").trim();
if (!trimmed) return "环";
// 取第一个字符(含中文);英文取大写
const ch = Array.from(trimmed)[0];
return /[a-z]/.test(ch) ? ch.toUpperCase() : ch;
}
export function EnvBadge({
envId,
name,
size = 24,
style,
}: {
envId: string;
name: string;
size?: number;
style?: CSSProperties;
}) {
const color = hashColor(envId);
return (
<span
className="env-badge"
style={{
width: size,
height: size,
fontSize: Math.round(size * 0.46),
background: `color-mix(in srgb, ${color} 16%, transparent)`,
color,
borderColor: `color-mix(in srgb, ${color} 40%, transparent)`,
...style,
}}
aria-hidden="true"
>
{firstChar(name)}
</span>
);
}