feat: P3 final batch - zoom, fonts, dark mode, tech debt cleanup

- Page zoom control (0.5-2.0x, localStorage)
- Custom monospace font selector (6 presets + custom)
- Element Plus dark mode final fixes (dropdown, message-box, switch, popper)
- AGENTS.md updated with correct paths + new modules/components/IPC channels
- ROADMAP: window state persistence already done via win-state.ts
- ROADMAP: tech debt items marked done
This commit is contained in:
2026-07-07 22:53:18 +08:00
parent 75c3a854d6
commit 71b2bd1771
7 changed files with 186 additions and 20 deletions
+49
View File
@@ -17,6 +17,15 @@ const locales = [
{ value: 'en', label: 'English' },
{ value: 'zh-CN', label: '中文' },
]
const fontOptions = [
'Cascadia Code',
'Fira Code',
'JetBrains Mono',
'Consolas',
'Monaco',
'Courier New',
]
</script>
<template>
@@ -61,6 +70,40 @@ const locales = [
size="small"
/>
</div>
<div class="settings-group">
<label class="settings-label">{{ t('settings.zoom') }}</label>
<el-slider
:model-value="appStore.zoom"
@update:model-value="appStore.setZoom($event)"
:min="0.5"
:max="2.0"
:step="0.1"
show-input
size="small"
style="width: 200px"
/>
<span class="zoom-value">{{ Math.round(appStore.zoom * 100) }}%</span>
</div>
<div class="settings-group">
<label class="settings-label">{{ t('settings.fontFamily') }}</label>
<el-select
:model-value="appStore.fontFamily"
@change="appStore.setFontFamily($event)"
size="small"
style="width: 180px"
allow-create
filterable
>
<el-option
v-for="font in fontOptions"
:key="font"
:label="font"
:value="font"
/>
</el-select>
</div>
</div>
</template>
@@ -89,4 +132,10 @@ const locales = [
color: var(--text-secondary);
min-width: 140px;
}
.zoom-value {
font-size: 12px;
color: var(--text-muted);
min-width: 40px;
}
</style>
+2
View File
@@ -299,5 +299,7 @@ export default {
language: 'Language',
scanCount: 'Keys per SCAN',
fontSize: 'Font Size',
zoom: 'Page Zoom',
fontFamily: 'Monospace Font',
},
}
+2
View File
@@ -299,5 +299,7 @@ export default {
language: '语言',
scanCount: 'SCAN 每次数量',
fontSize: '字体大小',
zoom: '页面缩放',
fontFamily: '等宽字体',
},
}
+19 -1
View File
@@ -9,6 +9,8 @@ export const useAppStore = defineStore('app', () => {
const isDark = ref(true)
const fontSize = ref<number>(Number(localStorage.getItem('fontSize')) || 13)
const scanCount = ref<number>(Number(localStorage.getItem('scanCount')) || 100)
const zoom = ref<number>(Number(localStorage.getItem('zoom')) || 1.0)
const fontFamily = ref<string>(localStorage.getItem('fontFamily') || 'Cascadia Code')
function applyTheme(mode: ThemeMode, osDark?: boolean) {
theme.value = mode
@@ -45,5 +47,21 @@ export const useAppStore = defineStore('app', () => {
localStorage.setItem('scanCount', String(count))
}
return { theme, isDark, fontSize, scanCount, setTheme, setFontSize, setScanCount }
function setZoom(value: number) {
zoom.value = value
localStorage.setItem('zoom', String(value))
document.body.style.zoom = String(value)
}
function setFontFamily(value: string) {
fontFamily.value = value
localStorage.setItem('fontFamily', value)
document.documentElement.style.setProperty('--font-mono', value)
}
// Apply saved zoom and fontFamily on mount
document.body.style.zoom = String(zoom.value)
document.documentElement.style.setProperty('--font-mono', fontFamily.value)
return { theme, isDark, fontSize, scanCount, zoom, fontFamily, setTheme, setFontSize, setScanCount, setZoom, setFontFamily }
})
+65
View File
@@ -291,3 +291,68 @@ body {
border-color: var(--border-color) !important;
color: var(--text-primary) !important;
}
/* Dropdown Menu */
.el-dropdown-menu {
background: var(--bg-secondary) !important;
border-color: var(--border-color) !important;
}
.el-dropdown-menu__item {
color: var(--text-primary) !important;
}
.el-dropdown-menu__item:not(.is-disabled):hover {
background: var(--bg-hover) !important;
color: var(--accent-light) !important;
}
/* Message Box */
.el-message-box {
background: var(--bg-secondary) !important;
border-color: var(--border-color) !important;
}
.el-message-box__title {
color: var(--text-primary) !important;
}
.el-message-box__message {
color: var(--text-primary) !important;
}
.el-message-box__content {
color: var(--text-primary) !important;
}
/* Switch */
.el-switch {
--el-switch-on-color: var(--accent) !important;
--el-switch-off-color: var(--bg-tertiary) !important;
}
.el-switch__core {
background: var(--bg-tertiary) !important;
border-color: var(--border-color) !important;
}
.el-switch.is-checked .el-switch__core {
background: var(--accent) !important;
border-color: var(--accent) !important;
}
/* Loading Mask */
.el-loading-mask {
background: rgba(0, 0, 0, 0.7) !important;
}
/* Popper (all popper types) */
.el-popper {
background: var(--bg-secondary) !important;
border-color: var(--border-color) !important;
}
.el-popper__arrow::before {
background: var(--bg-secondary) !important;
border-color: var(--border-color) !important;
}