Skip to content

Commit 8731414

Browse files
joshistoastlstein
andauthored
feat(hotkeys modal): ⚡ loading state + performance improvements (#8694)
* feat(hotkeys modal): ⚡ loading state + performance improvements * feat(hotkeys modal): add tooltip to edit button and adjust layout spacing * style(hotkeys modal): 🚨 satisfy the linter --------- Co-authored-by: Lincoln Stein <[email protected]>
1 parent 4cb9b8d commit 8731414

File tree

4 files changed

+201
-100
lines changed

4 files changed

+201
-100
lines changed

invokeai/frontend/web/src/features/system/components/HotkeysModal/HotkeyListItem.tsx

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import type { SystemStyleObject } from '@invoke-ai/ui-library';
22
import { Button, Flex, IconButton, Kbd, Text, Tooltip } from '@invoke-ai/ui-library';
3-
import { useAppDispatch } from 'app/store/storeHooks';
4-
import type { Hotkey } from 'features/system/components/HotkeysModal/useHotkeyData';
5-
import { IS_MAC_OS, useHotkeyConflictMap } from 'features/system/components/HotkeysModal/useHotkeyData';
3+
import type { AppThunkDispatch } from 'app/store/store';
4+
import type { Hotkey, HotkeyConflictInfo } from 'features/system/components/HotkeysModal/useHotkeyData';
5+
import { IS_MAC_OS } from 'features/system/components/HotkeysModal/useHotkeyData';
66
import { hotkeyChanged, hotkeyReset } from 'features/system/store/hotkeysSlice';
7+
import type { TFunction } from 'i18next';
78
import { Fragment, memo, useCallback, useEffect, useMemo, useState } from 'react';
8-
import { useTranslation } from 'react-i18next';
99
import {
1010
PiArrowCounterClockwiseBold,
1111
PiCheckBold,
@@ -82,8 +82,6 @@ type HotkeyEditProps = {
8282
onEditDelete?: (index: number) => void;
8383
};
8484

85-
type HotkeyConflictInfo = { category: string; id: string; title: string; fullId: string };
86-
8785
type HotkeyItemProps = HotkeyEditProps & {
8886
sx?: SystemStyleObject;
8987
keyString: string;
@@ -92,6 +90,7 @@ type HotkeyItemProps = HotkeyEditProps & {
9290
currentHotkeyId: string;
9391
isNewHotkey?: boolean;
9492
conflictMap: Map<string, HotkeyConflictInfo>;
93+
t: TFunction;
9594
};
9695

9796
const HotkeyRecorderSx: SystemStyleObject = {
@@ -126,8 +125,8 @@ const HotkeyItem = memo(
126125
currentHotkeyId,
127126
isNewHotkey,
128127
conflictMap,
128+
t,
129129
}: HotkeyItemProps) => {
130-
const { t } = useTranslation();
131130
const [recordedKey, setRecordedKey] = useState<string | null>(null);
132131
const [isRecording, setIsRecording] = useState(false);
133132

@@ -299,28 +298,30 @@ const HotkeyItem = memo(
299298
}
300299

301300
return (
302-
<Button
303-
variant="ghost"
304-
size="sm"
305-
onClick={onStartEdit}
306-
rightIcon={<PiPencilSimpleBold />}
307-
gap={0.5}
308-
alignItems="center"
309-
px={2}
310-
>
311-
{displayKeyParts.map((part, j) => (
312-
<Fragment key={j}>
313-
<Kbd fontSize="xs" textTransform="lowercase">
314-
{part}
315-
</Kbd>
316-
{j !== displayKeyParts.length - 1 && (
317-
<Text as="span" fontSize="xs" fontWeight="semibold" mx={0.5} mt={-0.5}>
318-
+
319-
</Text>
320-
)}
321-
</Fragment>
322-
))}
323-
</Button>
301+
<Tooltip label={t('hotkeys.editHotkey')}>
302+
<Button
303+
variant="ghost"
304+
size="sm"
305+
onClick={onStartEdit}
306+
rightIcon={<PiPencilSimpleBold />}
307+
gap={0.5}
308+
alignItems="center"
309+
px={2}
310+
>
311+
{displayKeyParts.map((part, j) => (
312+
<Fragment key={j}>
313+
<Kbd fontSize="xs" textTransform="lowercase">
314+
{part}
315+
</Kbd>
316+
{j !== displayKeyParts.length - 1 && (
317+
<Text as="span" fontSize="xs" fontWeight="semibold" mx={0.5} mt={-0.5}>
318+
+
319+
</Text>
320+
)}
321+
</Fragment>
322+
))}
323+
</Button>
324+
</Tooltip>
324325
);
325326
};
326327

@@ -380,6 +381,7 @@ type HotkeyItemsDisplayProps = HotkeyEditProps & {
380381
conflictMap: Map<string, HotkeyConflictInfo>;
381382
isCustomized?: boolean;
382383
onReset?: () => void;
384+
t: TFunction;
383385
};
384386

385387
const HotkeyItemsDisplaySx: SystemStyleObject = {
@@ -403,8 +405,8 @@ const HotkeyItemsDisplay = memo(
403405
conflictMap,
404406
isCustomized,
405407
onReset,
408+
t,
406409
}: HotkeyItemsDisplayProps) => {
407-
const { t } = useTranslation();
408410
const isAddingNew = editingIndex === hotkeys.length;
409411

410412
return (
@@ -422,6 +424,7 @@ const HotkeyItemsDisplay = memo(
422424
onEditDelete={onEditDelete}
423425
currentHotkeyId={currentHotkeyId}
424426
conflictMap={conflictMap}
427+
t={t}
425428
/>
426429
))
427430
: !isAddingNew && (
@@ -441,6 +444,7 @@ const HotkeyItemsDisplay = memo(
441444
currentHotkeyId={currentHotkeyId}
442445
isNewHotkey={true}
443446
conflictMap={conflictMap}
447+
t={t}
444448
/>
445449
)}
446450
<Flex>
@@ -476,23 +480,26 @@ const HotkeyItemsDisplay = memo(
476480
HotkeyItemsDisplay.displayName = 'HotkeyItemsDisplay';
477481

478482
type HotkeyListItemProps = {
483+
lastItem?: boolean;
479484
hotkey: Hotkey;
480485
sx?: SystemStyleObject;
486+
conflictMap: Map<string, HotkeyConflictInfo>;
487+
t: TFunction;
488+
dispatch: AppThunkDispatch;
481489
};
482490

483491
const HotkeyListItemSx: SystemStyleObject = {
484-
gap: 2,
485492
alignItems: 'start',
486493
justifyContent: 'space-between',
487494
width: '100%',
495+
py: 3,
496+
gap: 2,
488497
};
489498

490-
export const HotkeyListItem = memo(({ hotkey, sx }: HotkeyListItemProps) => {
499+
export const HotkeyListItem = memo(({ lastItem, hotkey, sx, conflictMap, t, dispatch }: HotkeyListItemProps) => {
491500
const { title, desc, hotkeys: hotkeyKeys, defaultHotkeys } = hotkey;
492501

493-
const dispatch = useAppDispatch();
494502
const [editingIndex, setEditingIndex] = useState<number | null>(null);
495-
const conflictMap = useHotkeyConflictMap();
496503

497504
// Check if hotkeys have been customized
498505
const isCustomized = useMemo(() => {
@@ -560,8 +567,8 @@ export const HotkeyListItem = memo(({ hotkey, sx }: HotkeyListItemProps) => {
560567
}, [dispatch, currentHotkeyId]);
561568

562569
return (
563-
<Flex sx={{ ...HotkeyListItemSx, ...sx }}>
564-
<Flex lineHeight={1} gap={1} w="100%" flexDir="column">
570+
<Flex sx={{ ...HotkeyListItemSx, borderBottomWidth: lastItem ? 0 : 1, ...sx }}>
571+
<Flex lineHeight={1} gap={2} w="100%" flexDir="column">
565572
<Text fontWeight="semibold">{title}</Text>
566573
<Text variant="subtext">{desc}</Text>
567574
</Flex>
@@ -578,6 +585,7 @@ export const HotkeyListItem = memo(({ hotkey, sx }: HotkeyListItemProps) => {
578585
conflictMap={conflictMap}
579586
isCustomized={isCustomized}
580587
onReset={handleReset}
588+
t={t}
581589
/>
582590
</Flex>
583591
</Flex>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import type { SystemStyleObject } from '@invoke-ai/ui-library';
2+
import type { AppThunkDispatch } from 'app/store/store';
3+
import type { Hotkey, HotkeyConflictInfo } from 'features/system/components/HotkeysModal/useHotkeyData';
4+
import { StickyScrollable } from 'features/system/components/StickyScrollable';
5+
import type { TFunction } from 'i18next';
6+
import { memo } from 'react';
7+
8+
import { HotkeyListItem } from './HotkeyListItem';
9+
10+
const HotkeyListWrapperContentSx: SystemStyleObject = {
11+
gap: 0,
12+
py: 0,
13+
};
14+
15+
const HotkeyListWrapperHeadingSx: SystemStyleObject = {
16+
py: 3,
17+
};
18+
19+
type HotkeysListWrapperProps = {
20+
title: string;
21+
hotkeysList: Hotkey[];
22+
conflictMap: Map<string, HotkeyConflictInfo>;
23+
t: TFunction;
24+
dispatch: AppThunkDispatch;
25+
};
26+
27+
export const HotkeysListWrapper = memo((props: HotkeysListWrapperProps) => {
28+
const { title, hotkeysList, conflictMap, t, dispatch } = props;
29+
30+
if (hotkeysList.length === 0) {
31+
return null;
32+
}
33+
34+
return (
35+
<StickyScrollable title={title} headingSx={HotkeyListWrapperHeadingSx} contentSx={HotkeyListWrapperContentSx}>
36+
{hotkeysList.map((hotkey, index) => (
37+
<HotkeyListItem
38+
key={hotkey.id}
39+
lastItem={index === hotkeysList.length - 1}
40+
hotkey={hotkey}
41+
conflictMap={conflictMap}
42+
t={t}
43+
dispatch={dispatch}
44+
/>
45+
))}
46+
</StickyScrollable>
47+
);
48+
});
49+
50+
HotkeysListWrapper.displayName = 'HotkeysListWrapper';

0 commit comments

Comments
 (0)