mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
refactor(memory-ui): replace emoji icons with inline SVG line-art
This commit is contained in:
parent
3157dde1f4
commit
7a650dc667
@ -39,7 +39,11 @@
|
||||
|
||||
<!-- Empty -->
|
||||
<div v-else-if="facts.length === 0" class="fact-empty">
|
||||
<div class="empty-icon">📦</div>
|
||||
<svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="21 8 21 21 3 21 3 8"/>
|
||||
<rect x="1" y="3" width="22" height="5"/>
|
||||
<line x1="10" y1="12" x2="14" y2="12"/>
|
||||
</svg>
|
||||
<p>{{ t('memory.facts.empty') }}</p>
|
||||
</div>
|
||||
|
||||
@ -58,9 +62,22 @@
|
||||
<FactTrustBar :trust="fact.trust" />
|
||||
<span class="fact-use-count" v-if="fact.useCount > 0">{{ t('memory.facts.used', { n: fact.useCount }) }}</span>
|
||||
<div class="fact-actions">
|
||||
<button class="action-btn helpful" @click="feedback(fact.id, 'HELPFUL')" :title="t('memory.facts.helpful')">👍</button>
|
||||
<button class="action-btn unhelpful" @click="feedback(fact.id, 'UNHELPFUL')" :title="t('memory.facts.unhelpful')">👎</button>
|
||||
<button class="action-btn forget" @click="forget(fact.id)" :title="t('memory.facts.forget')">🗑</button>
|
||||
<button class="action-btn helpful" @click="feedback(fact.id, 'HELPFUL')" :title="t('memory.facts.helpful')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="action-btn unhelpful" @click="feedback(fact.id, 'UNHELPFUL')" :title="t('memory.facts.unhelpful')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="action-btn forget" @click="forget(fact.id)" :title="t('memory.facts.forget')">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="3 6 5 6 21 6"/>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -187,11 +204,13 @@ async function resolve(contradictionId: number, resolution: string) {
|
||||
.fact-card:hover .fact-actions { opacity: 1; }
|
||||
.action-btn {
|
||||
width: 26px; height: 26px; display: flex; align-items: center; justify-content: center;
|
||||
border: none; border-radius: 6px; background: transparent; font-size: 13px;
|
||||
cursor: pointer; transition: background 0.12s;
|
||||
border: none; border-radius: 6px; background: transparent;
|
||||
color: var(--mc-text-tertiary); cursor: pointer; transition: all 0.12s;
|
||||
}
|
||||
.action-btn:hover { background: var(--mc-bg-elevated); }
|
||||
.action-btn.forget:hover { background: rgba(255,59,48,0.1); }
|
||||
.action-btn:hover { background: var(--mc-bg-elevated); color: var(--mc-text-secondary); }
|
||||
.action-btn.helpful:hover { color: #34c759; }
|
||||
.action-btn.unhelpful:hover { color: #ff9f0a; }
|
||||
.action-btn.forget:hover { background: rgba(255,59,48,0.1); color: #ff3b30; }
|
||||
|
||||
/* States */
|
||||
.fact-loading { padding: 8px 0; }
|
||||
@ -199,7 +218,7 @@ async function resolve(contradictionId: number, resolution: string) {
|
||||
.skeleton-line { height: 10px; border-radius: 4px; background: var(--mc-border-light); margin-bottom: 8px; }
|
||||
.skeleton-line.short { width: 60%; }
|
||||
.fact-empty { display: flex; flex-direction: column; align-items: center; padding: 40px 0; color: var(--mc-text-tertiary); }
|
||||
.empty-icon { font-size: 28px; margin-bottom: 8px; }
|
||||
.empty-icon { width: 32px; height: 32px; margin-bottom: 10px; opacity: 0.7; }
|
||||
|
||||
.slide-down-enter-active, .slide-down-leave-active { transition: all 0.2s ease; }
|
||||
.slide-down-enter-from, .slide-down-leave-to { opacity: 0; transform: translateY(-8px); }
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
class="file-nav-btn" :class="{ active: currentFile === f.filename }"
|
||||
:title="f.filename"
|
||||
@click="loadFile(f.filename)">
|
||||
<span class="file-nav-icon">{{ fileIcon(f.filename) }}</span>
|
||||
<span class="file-nav-icon" v-html="fileIcon(f.filename)" />
|
||||
<span class="file-nav-name">{{ fileLabel(f.filename) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -54,7 +54,12 @@
|
||||
|
||||
<!-- Empty -->
|
||||
<div v-else class="browser-empty">
|
||||
<div class="empty-icon">📝</div>
|
||||
<svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||
</svg>
|
||||
<p>{{ t('memory.memoryBrowser.empty') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -203,14 +208,24 @@ function renderMd(body: string): string {
|
||||
.join('')
|
||||
}
|
||||
|
||||
// Inline line-art icons (Feather style, 14px) keep the file tabs visually
|
||||
// consistent with the sidebar nav and the rest of the admin UI.
|
||||
function svgIcon(inner: string): string {
|
||||
return `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${inner}</svg>`
|
||||
}
|
||||
|
||||
function fileIcon(filename: string): string {
|
||||
if (filename === 'MEMORY.md') return '🧠'
|
||||
if (filename === 'PROFILE.md') return '👤'
|
||||
if (filename === 'SOUL.md') return '💫'
|
||||
if (filename === 'structured/user.md') return '📋'
|
||||
if (filename === 'structured/reference.md') return '🔗'
|
||||
if (filename.startsWith('structured/')) return '📋'
|
||||
return '📄'
|
||||
if (filename === 'MEMORY.md')
|
||||
return svgIcon('<path d="M12 2a4 4 0 0 1 4 4v2a4 4 0 0 1-8 0V6a4 4 0 0 1 4-4z"/><path d="M16 14H8a4 4 0 0 0-4 4v2h16v-2a4 4 0 0 0-4-4z"/><line x1="12" y1="11" x2="12" y2="14"/>')
|
||||
if (filename === 'PROFILE.md')
|
||||
return svgIcon('<circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/>')
|
||||
if (filename === 'SOUL.md')
|
||||
return svgIcon('<path d="M12 3l1.9 5.8a2 2 0 0 0 1.3 1.3L21 12l-5.8 1.9a2 2 0 0 0-1.3 1.3L12 21l-1.9-5.8a2 2 0 0 0-1.3-1.3L3 12l5.8-1.9a2 2 0 0 0 1.3-1.3L12 3z"/>')
|
||||
if (filename === 'structured/reference.md')
|
||||
return svgIcon('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>')
|
||||
if (filename.startsWith('structured/'))
|
||||
return svgIcon('<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>')
|
||||
return svgIcon('<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/>')
|
||||
}
|
||||
|
||||
// Rank for display order: 0 = primary brain, 1 = persona, 2 = extracted facts.
|
||||
@ -258,7 +273,7 @@ function fileLabel(filename: string): string {
|
||||
border-color: var(--mc-primary);
|
||||
color: var(--mc-text-primary);
|
||||
}
|
||||
.file-nav-icon { font-size: 14px; line-height: 1; }
|
||||
.file-nav-icon { display: inline-flex; align-items: center; }
|
||||
.file-nav-name { letter-spacing: 0.1px; }
|
||||
|
||||
/* Section cards */
|
||||
@ -327,5 +342,5 @@ function fileLabel(filename: string): string {
|
||||
.skeleton-line { height: 10px; border-radius: 4px; background: var(--mc-border-light); margin-bottom: 8px; }
|
||||
.skeleton-line.short { width: 60%; }
|
||||
.browser-empty { display: flex; flex-direction: column; align-items: center; padding: 40px 0; color: var(--mc-text-tertiary); }
|
||||
.empty-icon { font-size: 28px; margin-bottom: 8px; }
|
||||
.empty-icon { width: 32px; height: 32px; margin-bottom: 10px; color: var(--mc-text-tertiary); opacity: 0.7; }
|
||||
</style>
|
||||
|
||||
@ -2,7 +2,14 @@
|
||||
<Transition name="slide-down">
|
||||
<div v-if="card" class="morning-card">
|
||||
<div class="morning-card__header">
|
||||
<span class="morning-card__icon">🌅</span>
|
||||
<span class="morning-card__icon">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M17 18a5 5 0 0 0-10 0"/><line x1="12" y1="2" x2="12" y2="9"/>
|
||||
<line x1="4.22" y1="10.22" x2="5.64" y2="11.64"/><line x1="1" y1="18" x2="3" y2="18"/>
|
||||
<line x1="21" y1="18" x2="23" y2="18"/><line x1="18.36" y1="11.64" x2="19.78" y2="10.22"/>
|
||||
<line x1="23" y1="22" x2="1" y2="22"/><polyline points="8 6 12 2 16 6"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="morning-card__title">{{ t('memory.morningCard.title') }}</span>
|
||||
<button class="morning-card__close" @click="dismiss">×</button>
|
||||
</div>
|
||||
@ -54,7 +61,7 @@ async function dismiss() {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.morning-card__icon { font-size: 16px; }
|
||||
.morning-card__icon { display: inline-flex; align-items: center; color: var(--mc-primary); }
|
||||
.morning-card__title { flex: 1; font-size: 13px; font-weight: 600; color: var(--mc-text-primary); }
|
||||
.morning-card__close {
|
||||
background: none; border: none; font-size: 16px; color: var(--mc-text-tertiary);
|
||||
|
||||
@ -44,14 +44,19 @@
|
||||
</template>
|
||||
<template v-else-if="store.error">
|
||||
<div class="empty-state error-state">
|
||||
<div class="empty-icon">⚠️</div>
|
||||
<svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
||||
<line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>
|
||||
</svg>
|
||||
<p>{{ store.error }}</p>
|
||||
<button class="retry-btn" @click="loadReports">{{ t('memory.retry') }}</button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="store.reports.length === 0">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">🌙</div>
|
||||
<svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
||||
</svg>
|
||||
<p>{{ t('memory.noReports') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@ -145,7 +150,11 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="detail-empty">
|
||||
<div class="detail-empty-icon">🧠</div>
|
||||
<svg class="detail-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 2a4 4 0 0 1 4 4v2a4 4 0 0 1-8 0V6a4 4 0 0 1 4-4z"/>
|
||||
<path d="M16 14H8a4 4 0 0 0-4 4v2h16v-2a4 4 0 0 0-4-4z"/>
|
||||
<line x1="12" y1="11" x2="12" y2="14"/>
|
||||
</svg>
|
||||
<p>{{ t('memory.desc') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
@ -361,7 +370,7 @@ function fmtTime(iso: string) {
|
||||
.skeleton-line.short { width: 60%; }
|
||||
|
||||
.empty-state { display: flex; flex-direction: column; align-items: center; padding: 40px 0; color: var(--mc-text-tertiary); }
|
||||
.empty-icon { font-size: 28px; margin-bottom: 8px; }
|
||||
.empty-icon { width: 30px; height: 30px; margin-bottom: 10px; opacity: 0.7; }
|
||||
.empty-state p { font-size: 13px; }
|
||||
.error-state p { color: var(--mc-text-secondary); }
|
||||
.retry-btn {
|
||||
@ -447,7 +456,7 @@ function fmtTime(iso: string) {
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||
height: 100%; color: var(--mc-text-tertiary); text-align: center;
|
||||
}
|
||||
.detail-empty-icon { font-size: 36px; margin-bottom: 12px; }
|
||||
.detail-empty-icon { width: 40px; height: 40px; margin-bottom: 14px; opacity: 0.6; }
|
||||
.detail-empty p { font-size: 14px; max-width: 260px; line-height: 1.5; }
|
||||
|
||||
/* ========== Transitions ========== */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user