add first letter navigation, switch channels with ctrl k and not ctrl shift c
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user