mirror of
https://github.com/ILoveBingLu/CipherTalk.git
synced 2026-05-20 03:23:21 +08:00
feat: 更新版本号至2.2.12,新增窗口关闭行为配置选项
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
flex-direction: column;
|
||||
padding: 16px 0;
|
||||
transition: width 0.25s ease;
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
|
||||
&.collapsed {
|
||||
width: 64px;
|
||||
|
||||
+28
-25
@@ -711,17 +711,20 @@
|
||||
padding: 10px 24px;
|
||||
border-radius: 9999px;
|
||||
font-size: 14px;
|
||||
z-index: 100;
|
||||
z-index: 10000;
|
||||
animation: slideDown 0.3s ease;
|
||||
color: white;
|
||||
backdrop-filter: blur(24px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(24px) saturate(180%);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||
|
||||
&.success {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
background: rgba(var(--primary-rgb), 0.75);
|
||||
}
|
||||
|
||||
&.error {
|
||||
background: var(--danger);
|
||||
color: white;
|
||||
background: rgba(239, 68, 68, 0.75);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2046,17 +2049,17 @@ to {
|
||||
// 引用样式选择器
|
||||
.quote-style-options {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
|
||||
.radio-label {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
border-radius: 12px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
|
||||
background: linear-gradient(135deg, rgba(var(--primary-rgb), 0.08) 0%, rgba(var(--primary-rgb), 0.02) 100%);
|
||||
@@ -2107,14 +2110,14 @@ to {
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
|
||||
.radio-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
margin-top: 16px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.radio-desc {
|
||||
@@ -2126,22 +2129,22 @@ to {
|
||||
// 预览组件样式
|
||||
.style-preview {
|
||||
flex: 1;
|
||||
min-height: 80px;
|
||||
min-height: 60px;
|
||||
background: transparent;
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: flex-end;
|
||||
/* 靠右展示,模拟发送方 */
|
||||
padding: 16px 12px;
|
||||
justify-content: flex-start;
|
||||
/* 靠左展示,模拟接收方 */
|
||||
padding: 10px 8px;
|
||||
border: none;
|
||||
|
||||
.preview-avatar {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-tertiary);
|
||||
margin-left: 10px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
object-fit: cover;
|
||||
border: 1px solid var(--border-color);
|
||||
@@ -2154,10 +2157,10 @@ to {
|
||||
// 经典模式预览
|
||||
.preview-bubble.default {
|
||||
background: var(--primary);
|
||||
/* 使用主色调,模拟发送方 */
|
||||
/* 使用主色调,模拟接收方 */
|
||||
border: none;
|
||||
border-radius: 12px 12px 2px 12px;
|
||||
/* 真实气泡圆角 */
|
||||
border-radius: 12px 12px 12px 2px;
|
||||
/* 左下角小圆角,适合左边消息 */
|
||||
padding: 10px 12px;
|
||||
width: fit-content;
|
||||
max-width: 90%;
|
||||
@@ -2188,12 +2191,12 @@ to {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
align-items: flex-end;
|
||||
/* 模拟发送方 */
|
||||
align-items: flex-start;
|
||||
/* 模拟接收方 */
|
||||
|
||||
.preview-bubble.wechat {
|
||||
background: var(--primary);
|
||||
border-radius: 12px 12px 2px 12px;
|
||||
border-radius: 12px 12px 12px 2px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 4px;
|
||||
color: white;
|
||||
@@ -2205,7 +2208,7 @@ to {
|
||||
|
||||
.preview-quote-bubble {
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: 12px 4px 12px 12px;
|
||||
border-radius: 4px;
|
||||
padding: 4px 10px;
|
||||
width: fit-content;
|
||||
max-width: 90%;
|
||||
|
||||
+45
-10
@@ -103,6 +103,7 @@ function SettingsPage() {
|
||||
const [message, setMessage] = useState<{ text: string; success: boolean } | null>(null)
|
||||
const [showDecryptKey, setShowDecryptKey] = useState(false)
|
||||
const [showXorKey, setShowXorKey] = useState(false)
|
||||
const [closeToTray, setCloseToTray] = useState(true)
|
||||
const [showAesKey, setShowAesKey] = useState(false)
|
||||
const [showClearDialog, setShowClearDialog] = useState<{
|
||||
type: 'images' | 'emojis' | 'databases' | 'all' | 'config'
|
||||
@@ -225,6 +226,10 @@ function SettingsPage() {
|
||||
setAiEnableThinkingState(savedAiEnableThinking)
|
||||
setAiMessageLimitState(savedAiMessageLimit)
|
||||
|
||||
// 加载关闭行为配置
|
||||
const savedCloseToTray = await configService.getCloseToTray()
|
||||
setCloseToTray(savedCloseToTray)
|
||||
|
||||
} catch (e) {
|
||||
console.error('加载配置失败:', e)
|
||||
}
|
||||
@@ -762,6 +767,9 @@ function SettingsPage() {
|
||||
await configService.setAiEnableThinking(aiEnableThinking)
|
||||
await configService.setAiMessageLimit(aiMessageLimit)
|
||||
|
||||
// 保存关闭行为配置
|
||||
await configService.setCloseToTray(closeToTray)
|
||||
|
||||
// 如果数据库配置完整,尝试设置已连接状态(不进行耗时测试,仅标记)
|
||||
if (decryptKey && dbPath && wxid && decryptKey.length === 64 && isAccountVerified) {
|
||||
setDbConnected(true, dbPath)
|
||||
@@ -806,7 +814,7 @@ function SettingsPage() {
|
||||
|
||||
<h3 className="section-title" style={{ marginTop: '2rem' }}>应用图标</h3>
|
||||
<div className="quote-style-options">
|
||||
<label className={`radio-label ${appIcon === 'default' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '180px' }}>
|
||||
<label className={`radio-label ${appIcon === 'default' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '120px' }}>
|
||||
<input
|
||||
type="radio"
|
||||
name="appIcon"
|
||||
@@ -814,15 +822,14 @@ function SettingsPage() {
|
||||
checked={appIcon === 'default' || !appIcon}
|
||||
onChange={() => setAppIcon('default')}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">默认图标</span>
|
||||
<div className="radio-content" style={{ justifyContent: 'center' }}>
|
||||
<div className="style-preview" style={{ justifyContent: 'center', padding: '10px' }}>
|
||||
<img src="./logo.png" alt="默认" style={{ width: '48px', height: '48px' }} />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className={`radio-label ${appIcon === 'xinnian' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '180px' }}>
|
||||
<label className={`radio-label ${appIcon === 'xinnian' ? 'active' : ''}`} style={{ width: 'auto', minWidth: '120px' }}>
|
||||
<input
|
||||
type="radio"
|
||||
name="appIcon"
|
||||
@@ -830,8 +837,7 @@ function SettingsPage() {
|
||||
checked={appIcon === 'xinnian'}
|
||||
onChange={() => setAppIcon('xinnian')}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">新年图标</span>
|
||||
<div className="radio-content" style={{ justifyContent: 'center' }}>
|
||||
<div className="style-preview" style={{ justifyContent: 'center', padding: '10px' }}>
|
||||
<img src="./xinnian.png" alt="新年" style={{ width: '48px', height: '48px' }} />
|
||||
</div>
|
||||
@@ -850,8 +856,8 @@ function SettingsPage() {
|
||||
onChange={() => setQuoteStyle('default')}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">经典样式</span>
|
||||
<div className="style-preview">
|
||||
<img src="./logo.png" className="preview-avatar" alt="对方" />
|
||||
<div className="preview-bubble default">
|
||||
<div className="preview-quote">
|
||||
张三: 那天去爬山的照片...
|
||||
@@ -860,7 +866,6 @@ function SettingsPage() {
|
||||
拍得真不错!
|
||||
</div>
|
||||
</div>
|
||||
<img src="./logo.png" className="preview-avatar" alt="我" />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
@@ -874,8 +879,8 @@ function SettingsPage() {
|
||||
onChange={() => setQuoteStyle('wechat')}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">新版样式</span>
|
||||
<div className="style-preview">
|
||||
<img src="./logo.png" className="preview-avatar" alt="对方" />
|
||||
<div className="preview-group">
|
||||
<div className="preview-bubble wechat">
|
||||
拍得真不错!
|
||||
@@ -884,11 +889,41 @@ function SettingsPage() {
|
||||
张三: 那天去爬山的照片...
|
||||
</div>
|
||||
</div>
|
||||
<img src="./logo.png" className="preview-avatar" alt="我" />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h3 className="section-title" style={{ marginTop: '2rem' }}>窗口关闭行为</h3>
|
||||
<div className="quote-style-options">
|
||||
<label className={`radio-label ${closeToTray ? 'active' : ''}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="closeAction"
|
||||
value="tray"
|
||||
checked={closeToTray}
|
||||
onChange={() => setCloseToTray(true)}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">最小化到托盘</span>
|
||||
<span className="radio-desc">点击关闭按钮后,应用将最小化到系统托盘继续运行</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label className={`radio-label ${!closeToTray ? 'active' : ''}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="closeAction"
|
||||
value="quit"
|
||||
checked={!closeToTray}
|
||||
onChange={() => setCloseToTray(false)}
|
||||
/>
|
||||
<div className="radio-content">
|
||||
<span className="radio-title">直接退出应用</span>
|
||||
<span className="radio-desc">点击关闭按钮后,应用将完全退出</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
|
||||
+15
-1
@@ -31,7 +31,8 @@ export const CONFIG_KEYS = {
|
||||
AUTH_ENABLED: 'authEnabled',
|
||||
AUTH_CREDENTIAL_ID: 'authCredentialId',
|
||||
AUTH_PASSWORD_HASH: 'authPasswordHash',
|
||||
AUTH_PASSWORD_SALT: 'authPasswordSalt'
|
||||
AUTH_PASSWORD_SALT: 'authPasswordSalt',
|
||||
CLOSE_TO_TRAY: 'closeToTray'
|
||||
} as const
|
||||
|
||||
// 当前协议版本 - 更新协议内容时递增此版本号
|
||||
@@ -557,3 +558,16 @@ export async function loadAiConfigPreset(id: string): Promise<AiConfigPreset | n
|
||||
const presets = await getAiConfigPresets()
|
||||
return presets.find(p => p.id === id) || null
|
||||
}
|
||||
|
||||
// --- 窗口关闭行为配置 ---
|
||||
|
||||
// 获取关闭按钮行为(true: 最小化到托盘, false: 退出应用)
|
||||
export async function getCloseToTray(): Promise<boolean> {
|
||||
const value = await config.get(CONFIG_KEYS.CLOSE_TO_TRAY)
|
||||
return value !== undefined ? (value as boolean) : true
|
||||
}
|
||||
|
||||
// 设置关闭按钮行为
|
||||
export async function setCloseToTray(closeToTray: boolean): Promise<void> {
|
||||
await config.set(CONFIG_KEYS.CLOSE_TO_TRAY, closeToTray)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user