refactor: 将情景图标和设备选择器的 emoji 统一替换为 SVG 图标

- 新增 scenarioIcons.tsx 提取情景图标渲染逻辑
- 情景芯片、设备选择器、警告提示等 emoji 全部改为 Feather-style SVG
- 调整 CSS 确保 SVG 图标居中对齐
This commit is contained in:
2026-06-21 23:50:27 +08:00
parent 6cbabb63bb
commit e24fb2cc19
10 changed files with 232 additions and 75 deletions

View File

@@ -60,8 +60,8 @@ export const zhCN: TranslationMap = {
// Controls
"controls.connecting": "连接中...",
"controls.start": "🎙️ 开始对话",
"controls.startVideo": "🎙️ 开始视频通话",
"controls.start": "开始对话",
"controls.startVideo": "开始视频通话",
"controls.cameraOff": "关闭摄像头",
"controls.cameraOn": "开启摄像头",
"controls.micOff": "关闭麦克风",
@@ -70,7 +70,7 @@ export const zhCN: TranslationMap = {
"controls.stop": "结束对话",
"controls.stopVideo": "结束视频",
"controls.endSession": "结束会话",
"controls.resumeVideo": "📹 重新开始视频",
"controls.resumeVideo": "重新开始视频",
// Chat panel
"chat.title": "对话",

View File

@@ -0,0 +1,124 @@
// ============================================================
// scenarioIcons — 自建情景 SVG 图标集Feather-style
// 职责:为 CreateScenarioModal / EditScenarioModal 提供图标选项
// 为情景芯片条渲染自建情景的 SVG 图标
// ============================================================
import React from "react";
const P = { viewBox: "0 0 24 24", fill: "none" as const, stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round" as const, strokeLinejoin: "round" as const };
export interface ScenarioIconDef {
id: string;
label: string;
render: (size?: number) => React.ReactElement;
}
/** 自建情景可选的 Feather SVG 图标集 */
export const SCENARIO_ICON_SET: ScenarioIconDef[] = [
{
id: "sparkles", label: "通用助手",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5L12 3z"/><path d="M18 14l.75 2.25L21 17l-2.25.75L18 20l-.75-2.25L15 17l2.25-.75L18 14z"/><path d="M5 17l.5 1.5L7 19l-1.5.5L5 21l-.5-1.5L3 19l1.5-.5L5 17z"/></svg>),
},
{
id: "theater", label: "角色扮演",
render: (s = 16) => (<svg width={s} height={s} {...P}><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>),
},
{
id: "palette", label: "创意设计",
render: (s = 16) => (<svg width={s} height={s} {...P}><circle cx="13.5" cy="6.5" r=".5"/><circle cx="17.5" cy="10.5" r=".5"/><circle cx="8.5" cy="7.5" r=".5"/><circle cx="6.5" cy="12.5" r=".5"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.93 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.04-.23-.29-.38-.63-.38-1.04 0-.83.67-1.5 1.5-1.5H16c3.31 0 6-2.69 6-6 0-5.5-4.5-9.92-10-9.92z"/></svg>),
},
{
id: "target", label: "目标导向",
render: (s = 16) => (<svg width={s} height={s} {...P}><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>),
},
{
id: "film", label: "影视娱乐",
render: (s = 16) => (<svg width={s} height={s} {...P}><rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"/><line x1="7" y1="2" x2="7" y2="22"/><line x1="17" y1="2" x2="17" y2="22"/><line x1="2" y1="12" x2="22" y2="12"/><line x1="2" y1="7" x2="7" y2="7"/><line x1="2" y1="17" x2="7" y2="17"/><line x1="17" y1="17" x2="22" y2="17"/><line x1="17" y1="7" x2="22" y2="7"/></svg>),
},
{
id: "book-open", label: "阅读学习",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>),
},
{
id: "book", label: "教程指南",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>),
},
{
id: "edit", label: "写作编辑",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>),
},
{
id: "clipboard", label: "任务管理",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="2" width="8" height="4" rx="1" ry="1"/></svg>),
},
{
id: "map-pin", label: "导航定位",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>),
},
{
id: "search", label: "搜索探索",
render: (s = 16) => (<svg width={s} height={s} {...P}><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>),
},
{
id: "lightbulb", label: "灵感启发",
render: (s = 16) => (<svg width={s} height={s} {...P}><line x1="9" y1="18" x2="15" y2="18"/><line x1="10" y1="22" x2="14" y2="22"/><path d="M15.09 14c.18-.98.65-1.74 1.41-2.5A4.65 4.65 0 0 0 18 8 6 6 0 0 0 6 8c0 1 .23 2.23 1.5 3.5A4.61 4.61 0 0 1 8.91 14"/></svg>),
},
{
id: "briefcase", label: "商务办公",
render: (s = 16) => (<svg width={s} height={s} {...P}><rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg>),
},
{
id: "code", label: "编程开发",
render: (s = 16) => (<svg width={s} height={s} {...P}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>),
},
{
id: "graduation-cap", label: "教育培训",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c3 3 9 3 12 0v-5"/></svg>),
},
{
id: "mic", label: "语音对话",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/></svg>),
},
{
id: "music", label: "音乐艺术",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M9 18V5l12-2v13"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="16" r="3"/></svg>),
},
{
id: "globe", label: "翻译跨语言",
render: (s = 16) => (<svg width={s} height={s} {...P}><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>),
},
{
id: "heart", label: "健康关怀",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>),
},
{
id: "shield", label: "安全防护",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>),
},
{
id: "zap", label: "快速高效",
render: (s = 16) => (<svg width={s} height={s} {...P}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>),
},
{
id: "coffee", label: "休闲聊天",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M18 8h1a4 4 0 0 1 0 8h-1"/><path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4V8z"/><line x1="6" y1="1" x2="6" y2="4"/><line x1="10" y1="1" x2="10" y2="4"/><line x1="14" y1="1" x2="14" y2="4"/></svg>),
},
{
id: "tool", label: "工具助手",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>),
},
{
id: "message-circle", label: "对话问答",
render: (s = 16) => (<svg width={s} height={s} {...P}><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/></svg>),
},
];
/** 根据图标 ID 渲染 SVG找不到返回 null */
export function renderScenarioIconById(iconId: string, size = 14): React.ReactElement | null {
const def = SCENARIO_ICON_SET.find((d) => d.id === iconId);
return def ? def.render(size) : null;
}
/** 默认图标 ID */
export const DEFAULT_SCENARIO_ICON_ID = "sparkles";