-
-
Notifications
You must be signed in to change notification settings - Fork 808
Shortcut improvements #1573
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shortcut improvements #1573
Changes from 13 commits
84d0508
75ec976
f341887
c5c1d1d
3d10901
afe13a8
97e610a
747caa6
13232e2
2ac815f
bef4432
113d2e4
72d1381
277a69f
0958943
2a50b09
225eae8
3e27fe9
b937cce
e4446b2
4dcf218
ededd0d
f8e97c6
ba16fcc
fe31906
f189fc0
a1ec1c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { Keyboard } from "lucide-react"; | ||
import { Header3 } from "./primitives/Headers"; | ||
import { Paragraph } from "./primitives/Paragraph"; | ||
import { | ||
Sheet, | ||
SheetContent, | ||
SheetDescription, | ||
SheetHeader, | ||
SheetTitle, | ||
SheetTrigger, | ||
} from "./primitives/SheetV3"; | ||
import { ShortcutKey } from "./primitives/ShortcutKey"; | ||
import { Button } from "./primitives/Buttons"; | ||
|
||
export function Shortcuts() { | ||
return ( | ||
<Sheet> | ||
<SheetTrigger asChild> | ||
<Button | ||
variant="small-menu-item" | ||
LeadingIcon={Keyboard} | ||
leadingIconClassName="text-blue-500" | ||
data-action="shortcuts" | ||
fullWidth | ||
textAlignLeft | ||
shortcut={{ modifiers: ["shift"], key: "?" }} | ||
className="gap-x-0 pl-0.5" | ||
iconSpacing="gap-x-0.5" | ||
> | ||
Shortcuts | ||
</Button> | ||
</SheetTrigger> | ||
<SheetContent> | ||
<SheetHeader> | ||
<SheetTitle> | ||
<div className="flex items-center gap-x-2"> | ||
<Keyboard className="size-5 text-indigo-500" /> | ||
<span className="font-sans text-base font-medium text-text-bright"> | ||
Keyboard shortcuts | ||
</span> | ||
</div> | ||
</SheetTitle> | ||
<div className="space-y-6 px-4 py-2"> | ||
<div className="space-y-3"> | ||
<Header3>General</Header3> | ||
<Shortcut name="Close"> | ||
<ShortcutKey shortcut={{ key: "esc" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Confirm"> | ||
<ShortcutKey shortcut={{ key: "", modifiers: ["mod"] }} variant="medium/bright" /> | ||
<ShortcutKey shortcut={{ key: "enter" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Filter"> | ||
<ShortcutKey shortcut={{ key: "f" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Select filter"> | ||
<ShortcutKey shortcut={{ key: "1" }} variant="medium/bright" /> | ||
<Paragraph variant="small" className="ml-1"> | ||
to | ||
</Paragraph> | ||
<ShortcutKey shortcut={{ key: "9" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Previous page"> | ||
<ShortcutKey shortcut={{ key: "j" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Next page"> | ||
<ShortcutKey shortcut={{ key: "k" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Help & Feedback"> | ||
<ShortcutKey shortcut={{ key: "h" }} variant="medium/bright" /> | ||
</Shortcut> | ||
</div> | ||
<div className="space-y-3"> | ||
<Header3>Runs page</Header3> | ||
<Shortcut name="Bulk action: Cancel runs"> | ||
<ShortcutKey shortcut={{ key: "c" }} variant="medium/bright" /> | ||
</Shortcut> | ||
matt-aitken marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<Shortcut name="Bulk action: Replay runs"> | ||
<ShortcutKey shortcut={{ key: "r" }} variant="medium/bright" /> | ||
</Shortcut> | ||
matt-aitken marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<Shortcut name="Bulk action: Clear selection"> | ||
<ShortcutKey shortcut={{ key: "esc" }} variant="medium/bright" /> | ||
</Shortcut> | ||
</div> | ||
<div className="space-y-3"> | ||
<Header3>Run page</Header3> | ||
<Shortcut name="Replay run"> | ||
<ShortcutKey shortcut={{ key: "r" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Overview"> | ||
<ShortcutKey shortcut={{ key: "o" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Details"> | ||
<ShortcutKey shortcut={{ key: "d" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Context"> | ||
<ShortcutKey shortcut={{ key: "c" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Metadata"> | ||
<ShortcutKey shortcut={{ key: "m" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Navigate"> | ||
<ShortcutKey shortcut={{ key: "arrowup" }} variant="medium/bright" /> | ||
<ShortcutKey shortcut={{ key: "arrowdown" }} variant="medium/bright" /> | ||
<ShortcutKey shortcut={{ key: "arrowleft" }} variant="medium/bright" /> | ||
<ShortcutKey shortcut={{ key: "arrowright" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Expand all"> | ||
<ShortcutKey shortcut={{ key: "e" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Collapse all"> | ||
<ShortcutKey shortcut={{ key: "w" }} variant="medium/bright" /> | ||
</Shortcut> | ||
<Shortcut name="Toggle level"> | ||
<ShortcutKey shortcut={{ key: "0" }} variant="medium/bright" /> | ||
<Paragraph variant="small" className="ml-1"> | ||
to | ||
</Paragraph> | ||
<ShortcutKey shortcut={{ key: "9" }} variant="medium/bright" /> | ||
</Shortcut> | ||
</div> | ||
<div className="space-y-3"> | ||
<Header3>Schedules page</Header3> | ||
<Shortcut name="New schedule"> | ||
<ShortcutKey shortcut={{ key: "n" }} variant="medium/bright" /> | ||
</Shortcut> | ||
matt-aitken marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</div> | ||
<div className="space-y-3"> | ||
<Header3>Alerts page</Header3> | ||
<Shortcut name="New alert"> | ||
<ShortcutKey shortcut={{ key: "n" }} variant="medium/bright" /> | ||
</Shortcut> | ||
</div> | ||
</div> | ||
</SheetHeader> | ||
</SheetContent> | ||
</Sheet> | ||
); | ||
} | ||
|
||
function Shortcut({ children, name }: { children: React.ReactNode; name: string }) { | ||
return ( | ||
<div className="flex items-center justify-between gap-x-2"> | ||
<span className="text-sm text-text-dimmed">{name}</span> | ||
<span className="flex items-center gap-x-0.5">{children}</span> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,6 +4,7 @@ import { ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKeys"; | |||||||||||||||||||||||||||||||||||||||||||||||||
import { cn } from "~/utils/cn"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { IconNamesOrString, NamedIcon } from "./NamedIcon"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { ShortcutKey } from "./ShortcutKey"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./Tooltip"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const sizes = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
small: { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -65,8 +66,7 @@ const theme = { | |||||||||||||||||||||||||||||||||||||||||||||||||
icon: "text-text-bright", | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
minimal: { | ||||||||||||||||||||||||||||||||||||||||||||||||||
textColor: | ||||||||||||||||||||||||||||||||||||||||||||||||||
"text-text-dimmed group-hover/button:text-text-bright transition group-disabled/button:text-text-dimmed/80", | ||||||||||||||||||||||||||||||||||||||||||||||||||
textColor: "text-text-dimmed group-disabled/button:text-text-dimmed transition", | ||||||||||||||||||||||||||||||||||||||||||||||||||
button: | ||||||||||||||||||||||||||||||||||||||||||||||||||
"bg-transparent group-hover/button:bg-tertiary disabled:opacity-50 group-disabled/button:bg-transparent group-disabled/button:pointer-events-none", | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut: | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -173,8 +173,11 @@ export type ButtonContentPropsType = { | |||||||||||||||||||||||||||||||||||||||||||||||||
textAlignLeft?: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||
className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut?: ShortcutDefinition; | ||||||||||||||||||||||||||||||||||||||||||||||||||
showTooltip?: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||
variant: keyof typeof variant; | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcutPosition?: "before-trailing-icon" | "after-trailing-icon"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
tooltipDescription?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||
iconSpacing?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure 'tooltipDescription' is provided when 'showTooltip' is true When Apply this diff to update the type definition: export type ButtonContentPropsType = {
// existing props
showTooltip?: boolean;
- tooltipDescription?: string;
+ tooltipDescription?: string;
} & (
+ showTooltip extends true ? { tooltipDescription: string } : {}
); This change will enforce that
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @samejr same comment as above. Do we need both of these? Or should we just have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of being a string, it should be a React Node |
||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
export function ButtonContent(props: ButtonContentPropsType) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -188,23 +191,35 @@ export function ButtonContent(props: ButtonContentPropsType) { | |||||||||||||||||||||||||||||||||||||||||||||||||
fullWidth, | ||||||||||||||||||||||||||||||||||||||||||||||||||
textAlignLeft, | ||||||||||||||||||||||||||||||||||||||||||||||||||
className, | ||||||||||||||||||||||||||||||||||||||||||||||||||
showTooltip, | ||||||||||||||||||||||||||||||||||||||||||||||||||
tooltipDescription, | ||||||||||||||||||||||||||||||||||||||||||||||||||
iconSpacing, | ||||||||||||||||||||||||||||||||||||||||||||||||||
} = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const variation = allVariants.variant[props.variant]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
// Based on the size prop, we'll use the corresponding variant classnames | ||||||||||||||||||||||||||||||||||||||||||||||||||
const btnClassName = cn(allVariants.$all, variation.button); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const iconClassName = variation.icon; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const iconSpacingClassName = variation.iconSpacing; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const shortcutClassName = variation.shortcut; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const textColorClassName = variation.textColor; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
const renderShortcutKey = () => | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<ShortcutKey | ||||||||||||||||||||||||||||||||||||||||||||||||||
className={cn(shortcutClassName)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut={shortcut} | ||||||||||||||||||||||||||||||||||||||||||||||||||
variant={variation.shortcutVariant ?? "medium"} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const buttonContent = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<div className={cn("flex", fullWidth ? "" : "w-fit text-xxs", btnClassName, className)}> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<div | ||||||||||||||||||||||||||||||||||||||||||||||||||
className={cn( | ||||||||||||||||||||||||||||||||||||||||||||||||||
textAlignLeft ? "text-left" : "justify-center", | ||||||||||||||||||||||||||||||||||||||||||||||||||
"flex w-full items-center", | ||||||||||||||||||||||||||||||||||||||||||||||||||
iconSpacingClassName | ||||||||||||||||||||||||||||||||||||||||||||||||||
iconSpacingClassName, | ||||||||||||||||||||||||||||||||||||||||||||||||||
iconSpacing | ||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||
{LeadingIcon && | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -238,13 +253,10 @@ export function ButtonContent(props: ButtonContentPropsType) { | |||||||||||||||||||||||||||||||||||||||||||||||||
<>{text}</> | ||||||||||||||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
{shortcut && props.shortcutPosition === "before-trailing-icon" && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<ShortcutKey | ||||||||||||||||||||||||||||||||||||||||||||||||||
className={cn(shortcutClassName)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut={shortcut} | ||||||||||||||||||||||||||||||||||||||||||||||||||
variant={variation.shortcutVariant ?? "medium"} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
{shortcut && | ||||||||||||||||||||||||||||||||||||||||||||||||||
!showTooltip && | ||||||||||||||||||||||||||||||||||||||||||||||||||
props.shortcutPosition === "before-trailing-icon" && | ||||||||||||||||||||||||||||||||||||||||||||||||||
renderShortcutKey()} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
{TrailingIcon && | ||||||||||||||||||||||||||||||||||||||||||||||||||
(typeof TrailingIcon === "string" ? ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -269,16 +281,27 @@ export function ButtonContent(props: ButtonContentPropsType) { | |||||||||||||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
{shortcut && | ||||||||||||||||||||||||||||||||||||||||||||||||||
(!props.shortcutPosition || props.shortcutPosition === "after-trailing-icon") && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<ShortcutKey | ||||||||||||||||||||||||||||||||||||||||||||||||||
className={cn(shortcutClassName)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
shortcut={shortcut} | ||||||||||||||||||||||||||||||||||||||||||||||||||
variant={variation.shortcutVariant ?? "medium"} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
!showTooltip && | ||||||||||||||||||||||||||||||||||||||||||||||||||
(!props.shortcutPosition || props.shortcutPosition === "after-trailing-icon") && | ||||||||||||||||||||||||||||||||||||||||||||||||||
renderShortcutKey()} | ||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
if (shortcut && showTooltip) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<TooltipProvider> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<Tooltip> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<TooltipTrigger asChild>{buttonContent}</TooltipTrigger> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<TooltipContent className="text-dimmed flex items-center gap-3 py-1.5 pl-2.5 pr-3 text-xs"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
{tooltipDescription} {renderShortcutKey()} | ||||||||||||||||||||||||||||||||||||||||||||||||||
</TooltipContent> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</Tooltip> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</TooltipProvider> | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Handle undefined 'tooltipDescription' in tooltip rendering In the Modify the tooltip rendering logic as follows: <TooltipContent className="text-dimmed flex items-center gap-3 py-1.5 pl-2.5 pr-3 text-xs">
- {tooltipDescription} {renderShortcutKey()}
+ {tooltipDescription && <span>{tooltipDescription}</span>} {renderShortcutKey()}
</TooltipContent> This change ensures that the tooltip content is only rendered when 📝 Committable suggestion
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @samejr this is a good point. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return buttonContent; | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
type ButtonPropsType = Pick< | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.