fix(settings/overview): 清理 Windows 上不适用的 UI 选项/标签/布局 (#799)

* fix(hotkey): Windows 移除 Command 单键预设

Windows 没有 Command 键,leftCommand/rightCommand 会被映射到 Win 键,而单按 Win
弹出开始菜单,实际无法作为录音热键。从 Windows 的 available_triggers 里删掉这两个
预设,前端「常用单键」chip 便不再展示;不影响 HotkeyTrigger 枚举本身与已有绑定。

Fixes #784

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(settings/overview): 清理 Windows 上不适用的 UI 选项/标签/布局

- #783 补齐 hotkey.triggers 缺失的 leftShift/rightShift/leftCommand i18n(5 语言);
  之前缺 key 导致预设 chip 渲染成裸串 "hotkey.triggers.xxx"(用户看到的 "host…")
- #786 移除「粘贴快捷键」里的 Shift+Insert (xterm/urxvt) 选项——这组设置只在 Windows
  出现,而该选项是 X11 终端专用,放 Windows 上纯误导
- #785 删除「自动更新」下方错位的 hotkey statusHint(本属快捷键区,误挂到启动组)
- #780 「胶囊确认插入 ✓」速查行改为仅 macOS——Windows/Linux 胶囊无此按钮
- #781 「年度活动」卡片补 marginBottom,与上方卡片 18px 节奏一致
- #782 「近 7 天」卡片加 overflow:hidden,窗口过小时柱状图不再溢出卡片圆角外

Fixes #783, #786, #785, #780, #781, #782

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(settings): migrate removed Windows paste shortcut

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Chris233 <h-chris233@outlook.com>
This commit is contained in:
authored and GitHub committed 2026-07-14 10:04:56 +08:00
1 parent 01bff73cbe
commit a49d02b908
11 files changed
+50 -13

No files matched your search

+3 -2
View File
@@ -2576,12 +2576,13 @@ impl HotkeyCapability {
{
return Self {
adapter: HotkeyAdapterKind::WindowsLowLevel,
// Windows 没有 Command 键:leftCommand/rightCommand 会被映射到 Win 键,
// 而单按 Win 会弹出开始菜单,实际无法作为录音热键使用。故不在 Windows
// 的常用单键预设里提供 Command 选项(issue #784)。
available_triggers: vec![
HotkeyTrigger::RightControl,
HotkeyTrigger::RightAlt,
HotkeyTrigger::LeftControl,
HotkeyTrigger::RightCommand,
HotkeyTrigger::LeftCommand,
HotkeyTrigger::LeftShift,
HotkeyTrigger::RightShift,
HotkeyTrigger::MediaPlayPause,
+3
View File
@@ -1166,6 +1166,9 @@ export const en: typeof zhCN = {
rightControl: 'Right Control',
leftControl: 'Left Control',
rightCommand: 'Right Command',
leftCommand: 'Left Command',
leftShift: 'Left Shift',
rightShift: 'Right Shift',
fn: 'Fn (Globe key)',
rightAlt: 'Right Alt',
mediaPlayPause: '⏯ Media Play/Pause',
+3
View File
@@ -1134,6 +1134,9 @@ export const ja: typeof zhCN = {
rightControl: '右 Control',
leftControl: '左 Control',
rightCommand: '右 Command',
leftCommand: '左 Command',
leftShift: '左 Shift',
rightShift: '右 Shift',
fn: 'Fn (地球キー)',
rightAlt: '右 Alt',
mediaPlayPause: '⏯ メディア再生/一時停止',
+3
View File
@@ -1134,6 +1134,9 @@ export const ko: typeof zhCN = {
rightControl: '오른쪽 Control',
leftControl: '왼쪽 Control',
rightCommand: '오른쪽 Command',
leftCommand: '왼쪽 Command',
leftShift: '왼쪽 Shift',
rightShift: '오른쪽 Shift',
fn: 'Fn (지구본 키)',
rightAlt: '오른쪽 Alt',
mediaPlayPause: '⏯ 미디어 재생/일시정지',
+3
View File
@@ -1164,6 +1164,9 @@ export const zhCN = {
rightControl: '右 Control',
leftControl: '左 Control',
rightCommand: '右 Command',
leftCommand: '左 Command',
leftShift: '左 Shift',
rightShift: '右 Shift',
fn: 'Fn (地球键)',
rightAlt: '右 Alt',
mediaPlayPause: '⏯ 媒体播放/暂停',
+3
View File
@@ -1132,6 +1132,9 @@ export const zhTW: typeof zhCN = {
rightControl: '右 Control',
leftControl: '左 Control',
rightCommand: '右 Command',
leftCommand: '左 Command',
leftShift: '左 Shift',
rightShift: '右 Shift',
fn: 'Fn (地球鍵)',
rightAlt: '右 Alt',
mediaPlayPause: '⏯ 媒體播放/暫停',
+3 -1
View File
@@ -399,7 +399,9 @@ export const mockHotkeyCapability: HotkeyCapability = {
"rightControl",
"rightAlt",
"leftControl",
"rightCommand",
"leftShift",
"rightShift",
"mediaPlayPause",
"custom",
],
requiresAccessibilityPermission: false,
+6 -2
View File
@@ -219,7 +219,9 @@ export function Overview({ onOpenHistory }: OverviewProps) {
只有「最近识别」内部允许滚动;其他卡片按内容自然高度,不破裂底部圆角。
issue #243 follow-up:去掉外层 overflow 后底部圆角被裁的视觉问题。 */}
<div style={{ display: 'grid', gridTemplateColumns: mobile ? '1fr' : '1fr 1.4fr', gap: 12, flex: mobile ? undefined : 1, minHeight: mobile ? undefined : 0 }}>
<Card padding={18} style={{ display: 'flex', flexDirection: 'column', minHeight: 0 }}>
{/* overflow:hidden:窗口过小时这一行 flex:1 会被压到比内容还矮,柱状图(固定高)
原本会溢出卡片圆角外(issue #782)。裁进卡片内,与右侧「最近识别」卡片一致。 */}
<Card padding={18} style={{ display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14 }}>
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--ol-ink-2)' }}>{t('overview.weekTitle')}</span>
<span style={{ fontSize: 11, color: 'var(--ol-ink-4)' }}>{t('overview.weekUnit')}</span>
@@ -342,7 +344,9 @@ function ActivityHeatmapCard({ activity }: { activity: ActivityDay[] }) {
};
}, [activity, i18n.language]);
return (
<Card padding={18} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
// marginBottom 与上方 provider / metrics 两行的 18px 节奏保持一致:否则「年度活动」
// 会直接贴住下面「近 7 天 / 最近识别」那一行,中间没有间隔(issue #781)。
<Card padding={18} style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 18 }}>
<span style={{ fontSize: 12, fontWeight: 600, color: 'var(--ol-ink-2)' }}>
{t('overview.activityTitle')}
</span>
@@ -58,6 +58,18 @@ export function RecordingInputSection() {
void getPlatformCapabilities().then(setPlatformCaps);
}, []);
// 兼容旧 Windows 配置:Shift+Insert 仍保留在跨平台类型/后端中供 Linux 使用,
// 但 Windows 已不再提供该选项;进入设置时迁移为 Ctrl+V,避免下拉框无匹配值。
useEffect(() => {
if (os !== 'win' || prefs?.pasteShortcut !== 'shiftInsert') return;
void savePrefs(current => {
if (current.pasteShortcut !== 'shiftInsert') return current;
return { ...current, pasteShortcut: 'ctrlV' };
}).catch(error => {
console.warn('[settings] migrate Windows paste shortcut failed', error);
});
}, [os, prefs?.pasteShortcut, savePrefs]);
const loadMicrophoneDevices = useCallback(async (
signal?: { cancelled: boolean },
options: { showLoading?: boolean } = {},
@@ -133,6 +145,9 @@ export function RecordingInputSection() {
const showDesktopHotkey = platformCaps?.supportsDesktopHotkey === true;
const showDesktopInsert = showDesktopHotkey && os !== 'linux';
const showDesktopStartup = showDesktopHotkey;
const effectivePasteShortcut = os === 'win' && prefs.pasteShortcut === 'shiftInsert'
? 'ctrlV'
: prefs.pasteShortcut;
const onModeChange = (mode: HotkeyMode) =>
savePrefs({ ...prefs, hotkey: { ...prefs.hotkey, mode } });
@@ -309,12 +324,14 @@ export function RecordingInputSection() {
{capability.adapter !== 'macEventTap' && (
<SettingRow label={t('settings.recording.pasteShortcutLabel')} desc={t('settings.recording.pasteShortcutDesc')}>
<SelectLite
value={prefs.pasteShortcut}
value={effectivePasteShortcut}
onChange={next => onPasteShortcutChange(next as PasteShortcut)}
options={[
{ value: 'ctrlV', label: t('settings.recording.pasteShortcutCtrlV') },
{ value: 'ctrlShiftV', label: t('settings.recording.pasteShortcutCtrlShiftV') },
{ value: 'shiftInsert', label: t('settings.recording.pasteShortcutShiftInsert') },
// 这个「粘贴与剪贴板」组只在 Windows 出现(showDesktopInsert 已排除 Linux,mac 走
// macEventTap 不显示本行)。Shift+Insert 是 xterm/urxvt 等 X11 终端的粘贴组合,
// 放在 Windows 上纯属误导,故不再作为选项(issue #786)。
]}
ariaLabel={t('settings.recording.pasteShortcutLabel')}
style={{ ...inputStyle, maxWidth: 220 }}
@@ -404,11 +421,6 @@ export function RecordingInputSection() {
<SettingRow label={t('settings.recording.autoUpdateCheckLabel')}>
<Toggle on={prefs.autoUpdateCheck} onToggle={onAutoUpdateCheckChange} />
</SettingRow>
{capability.statusHint && (
<div style={{ marginTop: 6, fontSize: 11.5, color: 'var(--ol-ink-4)', lineHeight: 1.5 }}>
{capability.statusHint}
</div>
)}
</Collapsible>
)}
</>
@@ -62,7 +62,9 @@ export function ShortcutsSection() {
const readonlyRows: Array<[string, string]> = [
[t('settings.shortcuts.cancel'), 'Esc'],
...(os !== 'linux' ? [[t('settings.shortcuts.confirm'), t('settings.shortcuts.confirmHint')]] as Array<[string, string]> : []),
// 胶囊右侧「✓ 确认插入」目前只在 macOS 胶囊上有,Windows/Linux 胶囊没有这个按钮,
// 之前 os !== 'linux' 把它也展示给了 Windows,误导用户以为有个用不了的快捷键(issue #780)。
...(os === 'mac' ? [[t('settings.shortcuts.confirm'), t('settings.shortcuts.confirmHint')]] as Array<[string, string]> : []),
];
return (
<Card>
@@ -59,6 +59,7 @@ export function HotkeySettingsProvider({ children }: { children: ReactNode }) {
])
let nextError: string | null = null
if (prefsResult.status === "fulfilled") {
latestPrefsRef.current = prefsResult.value
setPrefs(prefsResult.value)
applyThemeFromPreference(prefsResult.value.themeMode ?? "system")
} else {