add first letter navigation, switch channels with ctrl k and not ctrl shift c

This commit is contained in:
2025-10-17 10:55:38 +02:00
parent 221aa1c2af
commit fca1046047
3 changed files with 64 additions and 8 deletions

View File

@@ -40,6 +40,11 @@ const props = defineProps<Props>()
const containerRef = ref<HTMLElement>()
const focusedChannelIndex = ref(0)
// For alphanumeric navigation
const lastSearchChar = ref('')
const lastSearchTime = ref(0)
const searchResetDelay = 1000 // Reset after 1 second
// Handle individual channel events
const handleChannelSelect = (channelId: number) => {
emit('select-channel', channelId)
@@ -103,6 +108,13 @@ const handleChannelKeydown = (event: KeyboardEvent, channelIndex: number) => {
break
default:
// Handle alphanumeric navigation (a-z, 0-9)
const char = event.key.toLowerCase()
if (/^[a-z0-9]$/.test(char)) {
event.preventDefault()
handleAlphanumericNavigation(char, channelIndex)
return
}
return
}
@@ -122,6 +134,41 @@ const focusChannel = (index: number) => {
})
}
const handleAlphanumericNavigation = (char: string, currentIndex: number) => {
if (props.channels.length === 0) return
const now = Date.now()
const sameChar = lastSearchChar.value === char && (now - lastSearchTime.value) < searchResetDelay
lastSearchChar.value = char
lastSearchTime.value = now
// Find channels starting with the character
const matchingIndices: number[] = []
props.channels.forEach((channel, index) => {
if (channel.name.toLowerCase().startsWith(char)) {
matchingIndices.push(index)
}
})
if (matchingIndices.length === 0) return
// If pressing the same character repeatedly, cycle through matches
if (sameChar) {
// Find the next match after current index
const nextMatch = matchingIndices.find(index => index > currentIndex)
if (nextMatch !== undefined) {
focusChannel(nextMatch)
} else {
// Wrap around to the first match
focusChannel(matchingIndices[0])
}
} else {
// New character: jump to first match
focusChannel(matchingIndices[0])
}
}
// Watch for channels changes and adjust focus
watch(() => props.channels.length, (newLength) => {

View File

@@ -44,7 +44,8 @@ export function useKeyboardShortcuts() {
// Allow certain shortcuts to work globally, even in input fields
const isGlobalShortcut = (shortcut.ctrlKey && shortcut.shiftKey) ||
shortcut.altKey ||
shortcut.key === 'escape'
shortcut.key === 'escape' ||
(shortcut.ctrlKey && shortcut.key === 'k')
// Skip shortcuts that shouldn't work in input fields
if (isInInputField && !isGlobalShortcut) {

View File

@@ -227,11 +227,10 @@ const setupKeyboardShortcuts = () => {
handler: () => { showSearchDialog.value = true }
})
// Ctrl+Shift+C - Channel selector focus
// Ctrl+K - Channel selector focus
addShortcut({
key: 'c',
key: 'k',
ctrlKey: true,
shiftKey: true,
handler: () => {
// Focus the first channel in the list
const firstChannelButton = document.querySelector('.channel-item button') as HTMLElement
@@ -557,6 +556,15 @@ const isUnsentMessage = (messageId: string | number): boolean => {
return typeof messageId === 'string' && messageId.startsWith('unsent_')
}
// Update document title when channel changes
watch(() => appStore.currentChannel, (channel) => {
if (channel) {
document.title = `${channel.name} - Notebrook`
} else {
document.title = 'Notebrook'
}
}, { immediate: true })
// Initialize
onMounted(async () => {
// 1. Load saved state first (offline-first)