mirror of
https://github.com/Mail-0/Zero.git
synced 2026-06-30 07:46:15 +00:00
feat: remove old hotkeys and add new View hotkeys (#1918)
# Add Numeric Hotkeys for Category Selection in Mail List ## Description This PR adds keyboard shortcuts for quickly toggling mail categories in the inbox view: - Numbers 1-9 toggle the corresponding categories (based on their index) - Number 0 clears all selected labels The implementation uses React Hotkeys Hook to register these shortcuts within the mail-list scope, making View switching much faster for keyboard-oriented users. ## Type of Change - [x] ✨ New feature (non-breaking change which adds functionality) - [x] 🎨 UI/UX improvement ## Areas Affected - [x] User Interface/Experience ## Testing Done - [x] Manual testing performed ## Checklist - [x] I have performed a self-review of my code - [x] My changes generate no new warnings <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added keyboard shortcuts (number keys 1–9) to quickly toggle category label filters in the mail category dropdown. * Added a keyboard shortcut (0 key) to clear all active category label filters. * **Refactor** * Disabled previous keyboard shortcuts for switching mail list categories to avoid conflicts and streamline shortcut behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -9,6 +9,7 @@ import { Bell, Lightning, Mail, ScanEye, Tag, User, X, Search } from '../icons/i
|
||||
import { useCategorySettings, useDefaultCategoryId } from '@/hooks/use-categories';
|
||||
import { ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable';
|
||||
import { useCommandPalette } from '../context/command-palette-context';
|
||||
import { useHotkeys, useHotkeysContext } from 'react-hotkeys-hook';
|
||||
import { ThreadDisplay } from '@/components/mail/thread-display';
|
||||
import { useActiveConnection } from '@/hooks/use-connections';
|
||||
import { Check, ChevronDown, RefreshCcw } from 'lucide-react';
|
||||
@@ -17,7 +18,6 @@ import useSearchLabels from '@/hooks/use-labels-search';
|
||||
import * as CustomIcons from '@/components/icons/icons';
|
||||
import { isMac } from '@/lib/hotkeys/use-hotkey-utils';
|
||||
import { MailList } from '@/components/mail/mail-list';
|
||||
import { useHotkeysContext } from 'react-hotkeys-hook';
|
||||
import { useNavigate, useParams } from 'react-router';
|
||||
import { useMail } from '@/components/mail/use-mail';
|
||||
import { SidebarToggle } from '../ui/sidebar-toggle';
|
||||
@@ -678,6 +678,42 @@ function CategoryDropdown({ isMultiSelectMode }: CategoryDropdownProps) {
|
||||
const folder = params?.folder ?? 'inbox';
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
categorySettings.forEach((category, index) => {
|
||||
if (index < 9) {
|
||||
const keyNumber = (index + 1).toString();
|
||||
useHotkeys(
|
||||
keyNumber,
|
||||
() => {
|
||||
const isCurrentlyActive = labels.includes(category.searchValue);
|
||||
|
||||
if (isCurrentlyActive) {
|
||||
setLabels(labels.filter((label) => label !== category.searchValue));
|
||||
} else {
|
||||
setLabels([...labels, category.searchValue]);
|
||||
}
|
||||
},
|
||||
{
|
||||
scopes: ['mail-list'],
|
||||
preventDefault: true,
|
||||
enableOnFormTags: false,
|
||||
},
|
||||
[category.searchValue, labels, setLabels], // Dependencies
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
useHotkeys(
|
||||
'0',
|
||||
() => {
|
||||
setLabels([]);
|
||||
},
|
||||
{
|
||||
scopes: ['mail-list'],
|
||||
preventDefault: true,
|
||||
enableOnFormTags: false,
|
||||
},
|
||||
);
|
||||
|
||||
if (folder !== 'inbox' || isMultiSelectMode) return null;
|
||||
|
||||
const handleLabelChange = (searchValue: string) => {
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { useOptimisticActions } from '@/hooks/use-optimistic-actions';
|
||||
import { enhancedKeyboardShortcuts } from '@/config/shortcuts';
|
||||
import { useSearchValue } from '@/hooks/use-search-value';
|
||||
import { useLocation, useParams } from 'react-router';
|
||||
// import { useSearchValue } from '@/hooks/use-search-value';
|
||||
import {
|
||||
// useLocation,
|
||||
useParams,
|
||||
} from 'react-router';
|
||||
import { useMail } from '@/components/mail/use-mail';
|
||||
import { useCallback, useMemo, useRef } from 'react';
|
||||
import { Categories } from '@/components/mail/mail';
|
||||
// import { Categories } from '@/components/mail/mail';
|
||||
import { useShortcuts } from './use-hotkey-utils';
|
||||
import { useThreads } from '@/hooks/use-threads';
|
||||
import { cleanSearchValue } from '@/lib/utils';
|
||||
// import { cleanSearchValue } from '@/lib/utils';
|
||||
import { m } from '@/paraglide/messages';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
@@ -16,9 +19,9 @@ export function MailListHotkeys() {
|
||||
const [mail, setMail] = useMail();
|
||||
const [, items] = useThreads();
|
||||
const hoveredEmailId = useRef<string | null>(null);
|
||||
const categories = Categories();
|
||||
const [searchValue, setSearchValue] = useSearchValue();
|
||||
const pathname = useLocation().pathname;
|
||||
// const categories = Categories();
|
||||
// const [searchValue, setSearchValue] = useSearchValue();
|
||||
// const pathname = useLocation().pathname;
|
||||
const params = useParams<{ folder: string }>();
|
||||
const folder = params?.folder ?? 'inbox';
|
||||
const shouldUseHover = mail.bulkSelected.length === 0;
|
||||
@@ -172,38 +175,38 @@ export function MailListHotkeys() {
|
||||
}));
|
||||
}, [shouldUseHover]);
|
||||
|
||||
const switchMailListCategory = useCallback(
|
||||
(category: string | null) => {
|
||||
if (pathname?.includes('/mail/inbox')) {
|
||||
const cat = categories.find((cat) => cat.id === category);
|
||||
if (!cat) {
|
||||
// setCategory(null);
|
||||
setSearchValue({
|
||||
value: '',
|
||||
highlight: searchValue.highlight,
|
||||
folder: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
// setCategory(cat.id);
|
||||
setSearchValue({
|
||||
value: `${cat.searchValue} ${cleanSearchValue(searchValue.value).trim().length ? `AND ${cleanSearchValue(searchValue.value)}` : ''}`,
|
||||
highlight: searchValue.highlight,
|
||||
folder: '',
|
||||
});
|
||||
}
|
||||
},
|
||||
[categories, pathname, searchValue, setSearchValue],
|
||||
);
|
||||
// const switchMailListCategory = useCallback(
|
||||
// (category: string | null) => {
|
||||
// if (pathname?.includes('/mail/inbox')) {
|
||||
// const cat = categories.find((cat) => cat.id === category);
|
||||
// if (!cat) {
|
||||
// // setCategory(null);
|
||||
// setSearchValue({
|
||||
// value: '',
|
||||
// highlight: searchValue.highlight,
|
||||
// folder: '',
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
// // setCategory(cat.id);
|
||||
// setSearchValue({
|
||||
// value: `${cat.searchValue} ${cleanSearchValue(searchValue.value).trim().length ? `AND ${cleanSearchValue(searchValue.value)}` : ''}`,
|
||||
// highlight: searchValue.highlight,
|
||||
// folder: '',
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// [categories, pathname, searchValue, setSearchValue],
|
||||
// );
|
||||
|
||||
const switchCategoryByIndex = useCallback(
|
||||
(idx: number) => {
|
||||
const cat = categories[idx];
|
||||
if (!cat) return;
|
||||
switchMailListCategory(cat.id);
|
||||
},
|
||||
[categories, switchMailListCategory],
|
||||
);
|
||||
// const switchCategoryByIndex = useCallback(
|
||||
// (idx: number) => {
|
||||
// const cat = categories[idx];
|
||||
// if (!cat) return;
|
||||
// switchMailListCategory(cat.id);
|
||||
// },
|
||||
// [categories, switchMailListCategory],
|
||||
// );
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
@@ -216,15 +219,15 @@ export function MailListHotkeys() {
|
||||
bulkDelete,
|
||||
bulkStar,
|
||||
exitSelectionMode,
|
||||
showImportant: () => switchCategoryByIndex(0),
|
||||
showAllMail: () => switchCategoryByIndex(1),
|
||||
showPersonal: () => switchCategoryByIndex(2),
|
||||
showUpdates: () => switchCategoryByIndex(3),
|
||||
showPromotions: () => switchCategoryByIndex(4),
|
||||
showUnread: () => switchCategoryByIndex(5),
|
||||
// showImportant: () => switchCategoryByIndex(0),
|
||||
// showAllMail: () => switchCategoryByIndex(1),
|
||||
// showPersonal: () => switchCategoryByIndex(2),
|
||||
// showUpdates: () => switchCategoryByIndex(3),
|
||||
// showPromotions: () => switchCategoryByIndex(4),
|
||||
// showUnread: () => switchCategoryByIndex(5),
|
||||
}),
|
||||
[
|
||||
switchCategoryByIndex,
|
||||
// switchCategoryByIndex,
|
||||
markAsRead,
|
||||
markAsUnread,
|
||||
markAsImportant,
|
||||
|
||||
Reference in New Issue
Block a user