Merge pull request #40 from Jasonzhu1207/refactor/ui-rebuild

Refactor/UI rebuild
This commit is contained in:
Jason authored and GitHub committed 2026-05-14 23:35:18 +08:00
commit ca1ef91bff
42 files changed
+4878 -3341

No files matched your search

+51 -46
View File
@@ -1698,6 +1698,7 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
if (selected) return
setQuoteLayout(option.value)
await configService.setQuoteLayout(option.value)
window.dispatchEvent(new CustomEvent('quote-layout-changed', { detail: option.value }))
showMessage(option.successMessage, true)
}}
role="radio"
@@ -1711,16 +1712,30 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
{isQuoteBottom ? (
<>
<div className="message-text">拍得真不错!</div>
<div className="quoted-message">
<span className="quoted-sender">张三</span>
<span className="quoted-text">那天去爬山的照片...</span>
<div className="ambient-reply-wrapper">
<div className="reply-anchor">
<svg className="reply-anchor-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="9 14 4 9 9 4" />
<path d="M20 20v-7a4 4 0 0 0-4-4H4" />
</svg>
<span className="reply-anchor-name">张三</span>
<span className="reply-anchor-sep">&middot;</span>
<span className="reply-anchor-excerpt">那天去爬山的照片...</span>
</div>
</div>
</>
) : (
<>
<div className="quoted-message">
<span className="quoted-sender">张三</span>
<span className="quoted-text">那天去爬山的照片...</span>
<div className="ambient-reply-wrapper">
<div className="reply-anchor">
<svg className="reply-anchor-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<polyline points="9 14 4 9 9 4" />
<path d="M20 20v-7a4 4 0 0 0-4-4H4" />
</svg>
<span className="reply-anchor-name">张三</span>
<span className="reply-anchor-sep">&middot;</span>
<span className="reply-anchor-excerpt">那天去爬山的照片...</span>
</div>
</div>
<div className="message-text">拍得真不错!</div>
</>
@@ -2212,23 +2227,32 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
/>
</div>
<div className="anti-revoke-toolbar-actions">
<div className="anti-revoke-btn-group">
<button className="btn btn-secondary btn-sm" onClick={() => void handleRefreshAntiRevokeStatus()} disabled={busy}>
<RefreshCw size={14} /> {isAntiRevokeRefreshing ? '刷新中...' : '刷新状态'}
</button>
</div>
<div className="anti-revoke-btn-group">
<button className="btn btn-secondary btn-sm" onClick={selectAllFiltered} disabled={busy || filteredSessionIds.length === 0 || allFilteredSelected}>
全选
</button>
<button className="btn btn-secondary btn-sm" onClick={clearSelection} disabled={busy || selectedCount === 0}>
清空选择
</button>
</div>
<button className="btn btn-secondary btn-sm" onClick={() => void handleRefreshAntiRevokeStatus()} disabled={busy}>
<RefreshCw size={14} /> {isAntiRevokeRefreshing ? '刷新中...' : '刷新状态'}
</button>
</div>
</div>
<div className="anti-revoke-selection-strip">
<div className="anti-revoke-selected-count">
<span>已选 <strong>{selectedCount}</strong> 个会话</span>
<span>筛选命中 <strong>{selectedInFilteredCount}</strong> / {filteredSessionIds.length}</span>
</div>
<div className="anti-revoke-selection-actions">
<button className="btn btn-secondary btn-sm" onClick={selectAllFiltered} disabled={busy || filteredSessionIds.length === 0 || allFilteredSelected}>
全选
</button>
<button className="btn btn-secondary btn-sm" onClick={clearSelection} disabled={busy || selectedCount === 0}>
清空选择
</button>
</div>
</div>
<div className="anti-revoke-batch-actions">
<div className="anti-revoke-batch-copy">
<span className="anti-revoke-section-label">批量部署</span>
<span>对已选会话执行防撤回安装或卸载</span>
</div>
<div className="anti-revoke-btn-group anti-revoke-batch-btns">
<button className="btn btn-primary btn-sm" onClick={() => void handleInstallAntiRevokeTriggers()} disabled={busy || selectedCount === 0}>
{isAntiRevokeInstalling ? '安装中...' : '批量安装'}
@@ -2237,10 +2261,6 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
{isAntiRevokeUninstalling ? '卸载中...' : '批量卸载'}
</button>
</div>
<div className="anti-revoke-selected-count">
<span>已选 <strong>{selectedCount}</strong> 个会话</span>
<span>筛选命中 <strong>{selectedInFilteredCount}</strong> / {filteredSessionIds.length}</span>
</div>
</div>
</div>
@@ -2539,11 +2559,6 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
const renderModelsTab = () => (
<div className="tab-content">
<div className="form-group">
<label>模型管理</label>
<span className="form-hint">管理语音识别模型</span>
</div>
<div className="form-group">
<label>语音识别模型 (Whisper)</label>
<span className="form-hint">用于语音消息转文字功能</span>
@@ -2561,12 +2576,6 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
) : (
<span className="status-indicator warning">未安装</span>
)}
{resolvedWhisperModelPath && (
<div className="model-path-block">
<span className="path-label">模型目录</span>
<div className="path-text" title={resolvedWhisperModelPath}>{resolvedWhisperModelPath}</div>
</div>
)}
</div>
</div>
{(!whisperModelStatus?.exists || isWhisperDownloading) && (
@@ -2597,25 +2606,21 @@ function SettingsPage({ onClose }: SettingsPageProps = {}) {
)}
</div>
)}
</div>
<div className="sub-setting">
<div className="sub-label">自定义模型目录</div>
<div className="path-selector">
<div className="model-directory-control">
<input
type="text"
value={whisperModelDir}
value={resolvedWhisperModelPath}
readOnly
placeholder="默认目录"
title={resolvedWhisperModelPath || '默认目录'}
/>
<button className="btn-icon" onClick={handleSelectWhisperModelDir} title="选择目录">
<FolderOpen size={18} />
<button className="btn btn-secondary btn-sm" onClick={handleSelectWhisperModelDir} title="选择自定义目录">
<FolderOpen size={14} /> 选择自定义目录
</button>
<button className="btn btn-secondary btn-sm" onClick={handleResetWhisperModelDir} disabled={!whisperModelDir} title="恢复默认">
<RotateCcw size={14} /> 恢复默认
</button>
{whisperModelDir && (
<button className="btn-icon danger" onClick={handleResetWhisperModelDir} title="重置为默认">
<RotateCcw size={18} />
</button>
)}
</div>
</div>
</div>