${escHtml(h.message)}
${h.hint ? `
${escHtml(h.hint)}
` : ''}
@@ -77,7 +78,7 @@ export function render() {
function renderBoard() {
if (!board?.columns?.length) {
- return `
📋
${escHtml(t('engine.hermesKanbanEmpty'))}
`
+ return `
${svgIcon('clipboard-list', { size: 32 })}
${escHtml(t('engine.hermesKanbanEmpty'))}
`
}
return `
@@ -107,7 +108,7 @@ export function render() {
${priorityBadge}
${assignee}
- ${task.comment_count ? `💬 ${task.comment_count}` : ''}
+ ${task.comment_count ? `${svgIcon('message-square', { size: 12 })} ${task.comment_count}` : ''}
`
diff --git a/src/engines/hermes/pages/lazy-deps.js b/src/engines/hermes/pages/lazy-deps.js
index 4681021..75a48f6 100644
--- a/src/engines/hermes/pages/lazy-deps.js
+++ b/src/engines/hermes/pages/lazy-deps.js
@@ -11,16 +11,17 @@ import { t } from '../../../lib/i18n.js'
import { api } from '../../../lib/tauri-api.js'
import { toast } from '../../../components/toast.js'
import { humanizeError } from '../../../lib/humanize-error.js'
+import { svgIcon } from '../lib/svg-icons.js'
// feature 分类配置(决定分组顺序 + 图标 + 文案)
const CATEGORIES = [
- { prefix: 'platform.', emoji: '💬', titleKey: 'hermesLazyDeps.catPlatform' },
- { prefix: 'tts.', emoji: '🔊', titleKey: 'hermesLazyDeps.catTts' },
- { prefix: 'stt.', emoji: '🎙️', titleKey: 'hermesLazyDeps.catStt' },
- { prefix: 'search.', emoji: '🔍', titleKey: 'hermesLazyDeps.catSearch' },
- { prefix: 'provider.', emoji: '🧠', titleKey: 'hermesLazyDeps.catProvider' },
- { prefix: 'memory.', emoji: '🗂️', titleKey: 'hermesLazyDeps.catMemory' },
- { prefix: 'image.', emoji: '🎨', titleKey: 'hermesLazyDeps.catImage' },
+ { prefix: 'platform.', icon: 'message-square', titleKey: 'hermesLazyDeps.catPlatform' },
+ { prefix: 'tts.', icon: 'volume', titleKey: 'hermesLazyDeps.catTts' },
+ { prefix: 'stt.', icon: 'mic', titleKey: 'hermesLazyDeps.catStt' },
+ { prefix: 'search.', icon: 'search', titleKey: 'hermesLazyDeps.catSearch' },
+ { prefix: 'provider.', icon: 'shield', titleKey: 'hermesLazyDeps.catProvider' },
+ { prefix: 'memory.', icon: 'inbox', titleKey: 'hermesLazyDeps.catMemory' },
+ { prefix: 'image.', icon: 'image', titleKey: 'hermesLazyDeps.catImage' },
]
const DESC_OVERRIDE_KEY = 'hermesLazyDeps.descOverride' // i18n.key 下的 feature → 描述
@@ -28,7 +29,7 @@ const DESC_OVERRIDE_KEY = 'hermesLazyDeps.descOverride' // i18n.key 下的 feat
// 把 feature 按分类分组
function groupByCategory(features) {
const groups = CATEGORIES.map(c => ({ ...c, items: [] }))
- const other = { prefix: '', emoji: '🧩', titleKey: 'hermesLazyDeps.catOther', items: [] }
+ const other = { prefix: '', icon: 'file', titleKey: 'hermesLazyDeps.catOther', items: [] }
for (const f of features) {
const cat = groups.find(g => f.feature.startsWith(g.prefix))
if (cat) cat.items.push(f)
@@ -83,7 +84,7 @@ async function loadAndRender(page) {
const features = featuresResp.features || []
if (!features.length) {
content.innerHTML = `
-
📦
+
${svgIcon('inbox', { size: 32 })}
${escapeHtml(t('hermesLazyDeps.emptyTitle'))}
`
return
@@ -113,7 +114,7 @@ function renderGroup(group, status) {
return `
- ${group.emoji}
+ ${svgIcon(group.icon, { size: 18 })}
${escapeHtml(t(group.titleKey))}
@@ -130,7 +131,7 @@ function renderItem(f, st) {
const specsTitle = (f.specs || []).join('\n')
const featureLabel = featureDisplayName(f.feature)
const stateBadge = satisfied
- ? `
✓ ${escapeHtml(t('hermesLazyDeps.installed'))}`
+ ? `
${svgIcon('check', { size: 11 })} ${escapeHtml(t('hermesLazyDeps.installed'))}`
: (known
? `
${escapeHtml(t('hermesLazyDeps.notInstalled'))}`
: `
?`)
diff --git a/src/engines/hermes/pages/logs.js b/src/engines/hermes/pages/logs.js
index ff1bce3..1929dc8 100644
--- a/src/engines/hermes/pages/logs.js
+++ b/src/engines/hermes/pages/logs.js
@@ -117,7 +117,7 @@ export function render() {
levelFilter !== 'ALL' ? levelFilter : null,
)
} catch (e) {
- entries = [{ raw: `⚠️ ${t('engine.logsLoadFailed')}: ${e.message || e}` }]
+ entries = [{ raw: `[ERROR] ${t('engine.logsLoadFailed')}: ${e.message || e}`, level: 'ERROR' }]
}
loading = false
draw()
diff --git a/src/engines/hermes/pages/oauth.js b/src/engines/hermes/pages/oauth.js
index baaece4..968b4de 100644
--- a/src/engines/hermes/pages/oauth.js
+++ b/src/engines/hermes/pages/oauth.js
@@ -15,6 +15,7 @@ import { api } from '../../../lib/tauri-api.js'
import { toast } from '../../../components/toast.js'
import { showModal, showContentModal } from '../../../components/modal.js'
import { humanizeError } from '../../../lib/humanize-error.js'
+import { svgIcon } from '../lib/svg-icons.js'
const OAUTH_BASE = '/api/providers/oauth'
@@ -27,7 +28,7 @@ function renderInlineError(err) {
const h = humanizeError(err, t('engine.hermesOAuthTitle'))
return `
-
⚠️
+
${svgIcon('alert-triangle', { size: 20 })}
${escHtml(h.message)}
${h.hint ? `
${escHtml(h.hint)}
` : ''}
@@ -62,7 +63,7 @@ export function render() {
${error ? renderInlineError(error) : ''}
${(!loading && !error && !providers.length) ? `
-
🔐
+
${svgIcon('lock', { size: 32 })}
${escHtml(t('engine.hermesOAuthEmpty'))}
` : ''}
${(!loading && providers.length) ? `
diff --git a/src/engines/hermes/pages/profiles.js b/src/engines/hermes/pages/profiles.js
index 153b183..e67ef41 100644
--- a/src/engines/hermes/pages/profiles.js
+++ b/src/engines/hermes/pages/profiles.js
@@ -16,6 +16,7 @@ import { toast } from '../../../components/toast.js'
import { showConfirm, showModal } from '../../../components/modal.js'
import { humanizeError } from '../../../lib/humanize-error.js'
import { getChatStore } from '../lib/chat-store.js'
+import { svgIcon } from '../lib/svg-icons.js'
const chatStore = getChatStore()
@@ -28,7 +29,7 @@ function renderInlineError(err) {
const h = humanizeError(err, t('engine.hermesProfilesTitle'))
return `
-
⚠️
+
${svgIcon('alert-triangle', { size: 20 })}
${escHtml(h.message)}
${h.hint ? `
${escHtml(h.hint)}
` : ''}
@@ -64,7 +65,7 @@ export function render() {
${error ? renderInlineError(error) : ''}
${(!loading && !error && !profiles.length) ? `
-
📁
+
${svgIcon('folder', { size: 32 })}
${escHtml(t('engine.hermesProfilesEmpty'))}
` : ''}
${(!loading && profiles.length) ? `
diff --git a/src/style/components.css b/src/style/components.css
index f8bd2d5..04fe822 100644
--- a/src/style/components.css
+++ b/src/style/components.css
@@ -438,6 +438,14 @@ mark {
margin-bottom: var(--space-md);
opacity: 0.85;
user-select: none;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-tertiary);
+}
+.empty-state .empty-icon svg {
+ width: 1em;
+ height: 1em;
}
.empty-state .empty-title {
diff --git a/src/style/pages.css b/src/style/pages.css
index f12dd26..6e4ce33 100644
--- a/src/style/pages.css
+++ b/src/style/pages.css
@@ -2675,6 +2675,14 @@
line-height: 1;
margin-top: 2px;
flex: 0 0 auto;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--error, #ef4444);
+}
+.page-inline-error-icon svg {
+ width: 20px;
+ height: 20px;
}
.page-inline-error-body {
flex: 1;