feat: Add searching of sub actions in command menu (#2845)

This commit is contained in:
Tom Moor
2021-12-11 09:34:16 -08:00
committed by GitHub
parent 7c6ce44fe1
commit e5b4186faa
7 changed files with 88 additions and 52 deletions

View File

@@ -23,7 +23,9 @@ function CommandBar() {
const { rootAction } = useKBar((state) => ({
rootAction: state.currentRootActionId
? (state.actions[state.currentRootActionId] as CommandBarAction)
? ((state.actions[
state.currentRootActionId
] as unknown) as CommandBarAction)
: undefined,
}));

View File

@@ -1,31 +1,55 @@
import { BackIcon } from "outline-icons";
import { ActionImpl } from "kbar";
import { ArrowIcon, BackIcon } from "outline-icons";
import * as React from "react";
import styled from "styled-components";
import styled, { css } from "styled-components";
import Flex from "~/components/Flex";
import Key from "~/components/Key";
import { CommandBarAction } from "~/types";
type Props = {
action: CommandBarAction;
action: ActionImpl;
active: boolean;
currentRootActionId: string | null | undefined;
};
function CommandBarItem(
{ action, active }: Props,
{ action, active, currentRootActionId }: Props,
ref: React.RefObject<HTMLDivElement>
) {
const ancestors = React.useMemo(() => {
if (!currentRootActionId) {
return action.ancestors;
}
const index = action.ancestors.findIndex(
(ancestor) => ancestor.id === currentRootActionId
);
// +1 removes the currentRootAction; e.g. if we are on the "Set theme"
// parent action, the UI should not display "Set theme… > Dark" but rather
// just "Dark"
return action.ancestors.slice(index + 1);
}, [action.ancestors, currentRootActionId]);
return (
<Item active={active} ref={ref}>
<Text align="center" gap={8}>
<Icon>
{action.icon ? (
// @ts-expect-error no icon on ActionImpl
React.cloneElement(action.icon, {
size: 22,
color: "currentColor",
})
) : (
<ForwardIcon color="currentColor" size={22} />
<ArrowIcon color="currentColor" />
)}
</Icon>
{ancestors.map((ancestor) => (
<React.Fragment key={ancestor.id}>
<Ancestor>{ancestor.name}</Ancestor>
<ForwardIcon color="currentColor" size={20} />
</React.Fragment>
))}
{action.name}
{action.children?.length ? "…" : ""}
</Text>
@@ -46,9 +70,16 @@ function CommandBarItem(
);
}
const Icon = styled.div`
width: 22px;
height: 22px;
const Icon = styled(Flex)`
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
color: ${(props) => props.theme.textSecondary};
flex-shrink: 0;
`;
const Ancestor = styled.span`
color: ${(props) => props.theme.textSecondary};
`;
@@ -60,7 +91,7 @@ const Text = styled(Flex)`
const Item = styled.div<{ active?: boolean }>`
font-size: 15px;
padding: 12px 16px;
padding: 10px 16px;
background: ${(props) =>
props.active ? props.theme.menuItemSelected : "none"};
display: flex;
@@ -72,10 +103,19 @@ const Item = styled.div<{ active?: boolean }>`
white-space: nowrap;
overflow: hidden;
min-width: 0;
${(props) =>
props.active &&
css`
${Icon} {
color: ${props.theme.text};
}
`}
`;
const ForwardIcon = styled(BackIcon)`
transform: rotate(180deg);
flex-shrink: 0;
`;
export default React.forwardRef<HTMLDivElement, Props>(CommandBarItem);

View File

@@ -1,33 +1,24 @@
import { useMatches, KBarResults, Action } from "kbar";
import { useMatches, KBarResults } from "kbar";
import * as React from "react";
import styled from "styled-components";
import CommandBarItem from "~/components/CommandBarItem";
import { CommandBarAction } from "~/types";
export default function CommandBarResults() {
const matches = useMatches();
const items = React.useMemo(
() =>
matches
.reduce((acc, curr) => {
const { actions, name } = curr;
acc.push(name);
acc.push(...actions);
return acc;
}, [] as (Action | string)[])
.filter((i) => i !== "none"),
[matches]
);
const { results, rootActionId } = useMatches();
return (
<KBarResults
items={items}
items={results}
maxHeight={400}
onRender={({ item, active }) =>
typeof item === "string" ? (
<Header>{item}</Header>
) : (
<CommandBarItem action={item as CommandBarAction} active={active} />
<CommandBarItem
action={item}
active={active}
currentRootActionId={rootActionId}
/>
)
}
/>

View File

@@ -1,5 +1,6 @@
import {
BookmarkedIcon,
BicycleIcon,
CollectionIcon,
CoinsIcon,
AcademicCapIcon,
@@ -26,6 +27,7 @@ import {
SportIcon,
SunIcon,
TargetIcon,
TerminalIcon,
ToolsIcon,
VehicleIcon,
WarningIcon,
@@ -74,6 +76,10 @@ export const icons = {
component: AcademicCapIcon,
keywords: "learn teach lesson guide tutorial onboarding training",
},
bicycle: {
component: BicycleIcon,
keywords: "bicycle bike cycle",
},
beaker: {
component: BeakerIcon,
keywords: "lab research experiment test",
@@ -162,6 +168,10 @@ export const icons = {
component: TargetIcon,
keywords: "target goal sales",
},
terminal: {
component: TerminalIcon,
keywords: "terminal code",
},
tools: {
component: ToolsIcon,
keywords: "tool settings",