2294 feat(frontend): styling shortcut keys (#2336)

* 2294 feat(frontend): styling shortcut keys

* 2294 fix(front): pr requested changes

* Fix component interface

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Kanav Arora 2023-11-09 19:48:51 +05:30 committed by GitHub
parent aa09b5758c
commit 279630052f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 52 deletions

View File

@ -88,13 +88,9 @@ export const CommandMenu = () => {
const activities = activityData?.searchResults ?? [];
const checkInShortcuts = (cmd: Command, search: string) => {
if (cmd.shortcuts && cmd.shortcuts.length > 0) {
return cmd.shortcuts
.join('')
.toLowerCase()
.includes(search.toLowerCase());
}
return false;
return (cmd.firstHotKey + (cmd.secondHotKey ?? ''))
.toLowerCase()
.includes(search.toLowerCase());
};
const checkInLabels = (cmd: Command, search: string) => {
@ -144,7 +140,8 @@ export const CommandMenu = () => {
Icon={cmd.Icon}
label={cmd.label}
onClick={cmd.onCommandClick}
shortcuts={cmd.shortcuts || []}
firstHotKey={cmd.firstHotKey}
secondHotKey={cmd.secondHotKey}
/>
))}
</CommandGroup>
@ -156,7 +153,8 @@ export const CommandMenu = () => {
label={cmd.label}
Icon={cmd.Icon}
onClick={cmd.onCommandClick}
shortcuts={cmd.shortcuts || []}
firstHotKey={cmd.firstHotKey}
secondHotKey={cmd.secondHotKey}
/>
))}
</CommandGroup>

View File

@ -12,7 +12,8 @@ export type CommandMenuItemProps = {
key: string;
onClick?: () => void;
Icon?: IconComponent;
shortcuts?: Array<string>;
firstHotKey?: string;
secondHotKey?: string;
};
export const CommandMenuItem = ({
@ -20,7 +21,8 @@ export const CommandMenuItem = ({
to,
onClick,
Icon,
shortcuts,
firstHotKey,
secondHotKey,
}: CommandMenuItemProps) => {
const navigate = useNavigate();
const { closeCommandMenu } = useCommandMenu();
@ -46,7 +48,8 @@ export const CommandMenuItem = ({
<MenuItemCommand
LeftIcon={Icon}
text={label}
command={shortcuts ? shortcuts.join(' then ') : ''}
firstHotKey={firstHotKey}
secondHotKey={secondHotKey}
onClick={onItemClick}
/>
);

View File

@ -13,35 +13,40 @@ export const commandMenuCommands: Command[] = [
to: '/people',
label: 'Go to People',
type: CommandType.Navigate,
shortcuts: ['G', 'P'],
firstHotKey: 'G',
secondHotKey: 'P',
Icon: IconUser,
},
{
to: '/companies',
label: 'Go to Companies',
type: CommandType.Navigate,
shortcuts: ['G', 'C'],
firstHotKey: 'G',
secondHotKey: 'C',
Icon: IconBuildingSkyscraper,
},
{
to: '/opportunities',
label: 'Go to Opportunities',
type: CommandType.Navigate,
shortcuts: ['G', 'O'],
firstHotKey: 'G',
secondHotKey: 'O',
Icon: IconTargetArrow,
},
{
to: '/settings/profile',
label: 'Go to Settings',
type: CommandType.Navigate,
shortcuts: ['G', 'S'],
firstHotKey: 'G',
secondHotKey: 'S',
Icon: IconSettings,
},
{
to: '/tasks',
label: 'Go to Tasks',
type: CommandType.Navigate,
shortcuts: ['G', 'T'],
firstHotKey: 'G',
secondHotKey: 'T',
Icon: IconCheckbox,
},
];

View File

@ -10,6 +10,7 @@ export type Command = {
label: string;
type: CommandType.Navigate | CommandType.Create;
Icon?: IconComponent;
shortcuts?: string[];
firstHotKey?: string;
secondHotKey?: string;
onCommandClick?: () => void;
};

View File

@ -9,6 +9,8 @@ import {
StyledMenuItemLeftContent,
} from '../internals/components/StyledMenuItemBase';
import { MenuItemCommandHotKeys } from './MenuItemCommandHotKeys';
const StyledMenuItemLabelText = styled(StyledMenuItemLabel)`
color: ${({ theme }) => theme.font.color.primary};
`;
@ -25,14 +27,6 @@ const StyledBigIconContainer = styled.div`
padding: ${({ theme }) => theme.spacing(1)};
`;
const StyledCommandText = styled.div`
color: ${({ theme }) => theme.font.color.light};
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
white-space: nowrap;
`;
const StyledMenuItemCommandContainer = styled(Command.Item)`
--horizontal-padding: ${({ theme }) => theme.spacing(1)};
--vertical-padding: ${({ theme }) => theme.spacing(2)};
@ -58,17 +52,6 @@ const StyledMenuItemCommandContainer = styled(Command.Item)`
}
&[data-selected='true'] {
background: ${({ theme }) => theme.background.tertiary};
/* Could be nice to add a caret like this for better accessibility in the future
But it needs to be consistend with other picker dropdown (e.g. company)
&:after {
background: ${({ theme }) => theme.background.quaternary};
content: '';
height: 100%;
left: 0;
position: absolute;
width: 3px;
z-index: ${({ theme }) => theme.lastLayerZIndex};
} */
}
&[data-disabled='true'] {
color: ${({ theme }) => theme.font.color.light};
@ -83,7 +66,8 @@ const StyledMenuItemCommandContainer = styled(Command.Item)`
export type MenuItemCommandProps = {
LeftIcon?: IconComponent;
text: string;
command: string;
firstHotKey?: string;
secondHotKey?: string;
className?: string;
onClick?: () => void;
};
@ -91,7 +75,8 @@ export type MenuItemCommandProps = {
export const MenuItemCommand = ({
LeftIcon,
text,
command,
firstHotKey,
secondHotKey,
className,
onClick,
}: MenuItemCommandProps) => {
@ -109,7 +94,10 @@ export const MenuItemCommand = ({
{text}
</StyledMenuItemLabelText>
</StyledMenuItemLeftContent>
<StyledCommandText>{command}</StyledCommandText>
<MenuItemCommandHotKeys
firstHotKey={firstHotKey}
secondHotKey={secondHotKey}
/>
</StyledMenuItemCommandContainer>
);
};

View File

@ -0,0 +1,62 @@
import styled from '@emotion/styled';
const StyledCommandTextContainer = styled.div`
align-items: center;
display: flex;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(1)};
justify-content: center;
`;
const StyledCommandText = styled.div`
color: ${({ theme }) => theme.font.color.light};
padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(1)};
white-space: nowrap;
`;
const StyledCommandKey = styled.div`
align-items: center;
background-color: ${({ theme }) => theme.background.secondary};
border: 1px solid ${({ theme }) => theme.border.color.strong};
border-radius: ${({ theme }) => theme.border.radius.sm};
box-shadow: ${({ theme }) => theme.boxShadow.underline};
display: flex;
flex-direction: column;
height: ${({ theme }) => theme.spacing(5)};
height: 18px;
justify-content: center;
text-align: center;
width: ${({ theme }) => theme.spacing(4)};
`;
export type MenuItemCommandHotKeysProps = {
firstHotKey?: string;
joinLabel?: string;
secondHotKey?: string;
};
export const MenuItemCommandHotKeys = ({
firstHotKey,
secondHotKey,
joinLabel = 'then',
}: MenuItemCommandHotKeysProps) => {
return (
<StyledCommandText>
{firstHotKey && (
<StyledCommandTextContainer>
<StyledCommandKey>{firstHotKey}</StyledCommandKey>
{secondHotKey && (
<>
{joinLabel}
<StyledCommandKey>{secondHotKey}</StyledCommandKey>
</>
)}
</StyledCommandTextContainer>
)}
</StyledCommandText>
);
};

View File

@ -20,14 +20,16 @@ type Story = StoryObj<typeof MenuItemCommand>;
export const Default: Story = {
args: {
text: 'First option',
command: '⌘ 1',
firstHotKey: '⌘',
secondHotKey: '1',
},
render: (props) => (
<Command>
<MenuItemCommand
LeftIcon={props.LeftIcon}
text={props.text}
command={props.text}
firstHotKey={props.firstHotKey}
secondHotKey={props.secondHotKey}
className={props.className}
onClick={props.onClick}
></MenuItemCommand>
@ -37,12 +39,16 @@ export const Default: Story = {
};
export const Catalog: CatalogStory<Story, typeof MenuItemCommand> = {
args: { LeftIcon: IconBell, text: 'Menu item', command: '⌘1' },
args: {
text: 'Menu item',
firstHotKey: '⌘',
secondHotKey: '1',
},
argTypes: {
className: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.pressed'], focus: ['.focus'] },
pseudo: { hover: ['.hover'] },
catalog: {
dimensions: [
{
@ -54,13 +60,6 @@ export const Catalog: CatalogStory<Story, typeof MenuItemCommand> = {
labels: (withIcon: boolean) =>
withIcon ? 'With left icon' : 'Without left icon',
},
{
name: 'selected',
values: [true, false],
props: () => ({}),
labels: (selected: boolean) =>
selected ? 'Selected' : 'Not selected',
},
{
name: 'states',
values: ['default', 'hover'],
@ -88,7 +87,8 @@ export const Catalog: CatalogStory<Story, typeof MenuItemCommand> = {
<MenuItemCommand
LeftIcon={props.LeftIcon}
text={props.text}
command={props.text}
firstHotKey={props.firstHotKey}
secondHotKey={props.secondHotKey}
className={props.className}
onClick={props.onClick}
></MenuItemCommand>

View File

@ -10,6 +10,7 @@ export const boxShadowLight = {
grayScale.gray100,
0.12,
)}, 0px 2px 4px 0px ${rgba(grayScale.gray100, 0.04)}`,
underline: `0px 1px 0px 0px ${rgba(grayScale.gray100, 0.32)}`,
};
export const boxShadowDark = {
@ -22,4 +23,5 @@ export const boxShadowDark = {
grayScale.gray100,
0.16,
)}, 0px 2px 4px 0px ${rgba(grayScale.gray100, 0.08)}`,
underline: `0px 1px 0px 0px ${rgba(grayScale.gray100, 0.32)}`,
};