feat: global shortcut for quick entry dialog

This commit is contained in:
Your Name
2026-02-20 15:20:27 +02:00
parent 96ef48000c
commit f337f8c28f
2 changed files with 33 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
import TitleBar from './components/TitleBar.vue' import TitleBar from './components/TitleBar.vue'
import NavRail from './components/NavRail.vue' import NavRail from './components/NavRail.vue'
@@ -16,6 +16,7 @@ import type { SoundEvent } from './utils/audio'
import TourOverlay from './components/TourOverlay.vue' import TourOverlay from './components/TourOverlay.vue'
import RecurringPromptDialog from './components/RecurringPromptDialog.vue' import RecurringPromptDialog from './components/RecurringPromptDialog.vue'
import TimerSaveDialog from './components/TimerSaveDialog.vue' import TimerSaveDialog from './components/TimerSaveDialog.vue'
import QuickEntryDialog from './components/QuickEntryDialog.vue'
import { useOnboardingStore } from './stores/onboarding' import { useOnboardingStore } from './stores/onboarding'
import { useProjectsStore } from './stores/projects' import { useProjectsStore } from './stores/projects'
import { useInvoicesStore } from './stores/invoices' import { useInvoicesStore } from './stores/invoices'
@@ -24,6 +25,7 @@ const settingsStore = useSettingsStore()
const recurringStore = useRecurringStore() const recurringStore = useRecurringStore()
const timerStore = useTimerStore() const timerStore = useTimerStore()
const { announcement } = useAnnouncer() const { announcement } = useAnnouncer()
const showQuickEntry = ref(false)
function getProjectName(projectId?: number): string { function getProjectName(projectId?: number): string {
if (!projectId) return '' if (!projectId) return ''
@@ -59,6 +61,15 @@ async function registerShortcuts() {
await win.show() await win.show()
await win.setFocus() await win.setFocus()
}) })
const quickEntryKey = settingsStore.settings.shortcut_quick_entry || 'CmdOrCtrl+Shift+N'
await register(quickEntryKey, async () => {
const { getCurrentWindow } = await import('@tauri-apps/api/window')
const win = getCurrentWindow()
await win.show()
await win.setFocus()
showQuickEntry.value = true
})
} catch (e) { } catch (e) {
console.error('Failed to register shortcuts:', e) console.error('Failed to register shortcuts:', e)
} }
@@ -215,7 +226,7 @@ watch(() => settingsStore.settings.ui_font, (newFont) => {
} }
}) })
watch(() => [settingsStore.settings.shortcut_toggle_timer, settingsStore.settings.shortcut_show_app], () => { watch(() => [settingsStore.settings.shortcut_toggle_timer, settingsStore.settings.shortcut_show_app, settingsStore.settings.shortcut_quick_entry], () => {
registerShortcuts() registerShortcuts()
}) })
@@ -284,6 +295,11 @@ watch(() => settingsStore.settings.persistent_notifications, (val) => {
@discard="timerStore.handleSaveDialogDiscard" @discard="timerStore.handleSaveDialogDiscard"
@cancel="timerStore.handleSaveDialogCancel" @cancel="timerStore.handleSaveDialogCancel"
/> />
<QuickEntryDialog
:show="showQuickEntry"
@close="showQuickEntry = false"
@saved="showQuickEntry = false"
/>
<div id="route-announcer" class="sr-only" aria-live="polite" aria-atomic="true"></div> <div id="route-announcer" class="sr-only" aria-live="polite" aria-atomic="true"></div>
<div id="announcer" class="sr-only" aria-live="assertive" aria-atomic="true">{{ announcement }}</div> <div id="announcer" class="sr-only" aria-live="assertive" aria-atomic="true">{{ announcement }}</div>
<TourOverlay /> <TourOverlay />

View File

@@ -570,6 +570,18 @@
/> />
</div> </div>
<div class="flex items-center justify-between">
<div>
<p class="text-[0.8125rem] text-text-primary">Quick Entry</p>
<p class="text-[0.6875rem] text-text-tertiary mt-0.5">Open quick entry dialog from anywhere</p>
</div>
<AppShortcutRecorder
:model-value="shortcutQuickEntry"
@update:model-value="(v: string) => { shortcutQuickEntry = v; saveShortcutSettings() }"
label="Quick entry shortcut"
/>
</div>
<!-- Divider --> <!-- Divider -->
<div class="border-t border-border-subtle" /> <div class="border-t border-border-subtle" />
@@ -1414,6 +1426,7 @@ const themeMode = ref('dark')
const accentColor = ref('amber') const accentColor = ref('amber')
const shortcutToggleTimer = ref('CmdOrCtrl+Shift+T') const shortcutToggleTimer = ref('CmdOrCtrl+Shift+T')
const shortcutShowApp = ref('CmdOrCtrl+Shift+Z') const shortcutShowApp = ref('CmdOrCtrl+Shift+Z')
const shortcutQuickEntry = ref('CmdOrCtrl+Shift+N')
const timelineRecording = ref(false) const timelineRecording = ref(false)
const timerFont = ref('JetBrains Mono') const timerFont = ref('JetBrains Mono')
const timerFontOptions = TIMER_FONTS const timerFontOptions = TIMER_FONTS
@@ -1779,6 +1792,7 @@ async function saveUIFontSetting() {
async function saveShortcutSettings() { async function saveShortcutSettings() {
await settingsStore.updateSetting('shortcut_toggle_timer', shortcutToggleTimer.value) await settingsStore.updateSetting('shortcut_toggle_timer', shortcutToggleTimer.value)
await settingsStore.updateSetting('shortcut_show_app', shortcutShowApp.value) await settingsStore.updateSetting('shortcut_show_app', shortcutShowApp.value)
await settingsStore.updateSetting('shortcut_quick_entry', shortcutQuickEntry.value)
} }
// Save timer font setting // Save timer font setting
@@ -2124,6 +2138,7 @@ onMounted(async () => {
accentColor.value = settingsStore.settings.accent_color || 'amber' accentColor.value = settingsStore.settings.accent_color || 'amber'
shortcutToggleTimer.value = settingsStore.settings.shortcut_toggle_timer || 'CmdOrCtrl+Shift+T' shortcutToggleTimer.value = settingsStore.settings.shortcut_toggle_timer || 'CmdOrCtrl+Shift+T'
shortcutShowApp.value = settingsStore.settings.shortcut_show_app || 'CmdOrCtrl+Shift+Z' shortcutShowApp.value = settingsStore.settings.shortcut_show_app || 'CmdOrCtrl+Shift+Z'
shortcutQuickEntry.value = settingsStore.settings.shortcut_quick_entry || 'CmdOrCtrl+Shift+N'
dailyGoalHours.value = parseFloat(settingsStore.settings.daily_goal_hours) || 8 dailyGoalHours.value = parseFloat(settingsStore.settings.daily_goal_hours) || 8
weeklyGoalHours.value = parseFloat(settingsStore.settings.weekly_goal_hours) || 40 weeklyGoalHours.value = parseFloat(settingsStore.settings.weekly_goal_hours) || 40
roundingEnabled.value = settingsStore.settings.rounding_enabled === 'true' roundingEnabled.value = settingsStore.settings.rounding_enabled === 'true'