Skip to content

Commit

Permalink
Fix Kbar in operator mode (#1638)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
  • Loading branch information
dvaldivia committed Mar 1, 2022
1 parent d82bd31 commit 19dd7aa
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 248 deletions.
218 changes: 218 additions & 0 deletions portal-ui/src/screens/Console/CommandBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import * as React from "react";
import {
ActionId,
ActionImpl,
KBarAnimator,
KBarPortal,
KBarPositioner,
KBarResults,
KBarSearch,
useMatches,
useRegisterActions,
} from "kbar";
import { Action } from "kbar/lib/types";
import { Theme } from "@mui/material/styles";
import makeStyles from "@mui/styles/makeStyles";
import { routesAsKbarActions } from "./kbar-actions";

const useStyles = makeStyles((theme: Theme) => ({
resultItem: {
display: "flex",
gap: "8px",
alignItems: "center",
fontSize: 14,
"& .min-icon": {
color: theme.palette.primary.main,
width: "18px",
height: "18px",
},
},
}));

const searchStyle = {
padding: "12px 16px",
fontSize: "16px",
width: "100%",
boxSizing: "border-box" as React.CSSProperties["boxSizing"],
outline: "none",
border: "none",
background: "transparent",
color: "#111111",
};

const animatorStyle = {
maxWidth: "600px",
width: "100%",
background: "white",
color: "black",
borderRadius: "8px",
overflow: "hidden",
boxShadow: "rgba(0, 0, 0, 0.2) 0px 6px 20px 0px",
};

const groupNameStyle = {
padding: "8px 16px",
fontSize: "10px",
textTransform: "uppercase" as const,
opacity: 0.5,
};

const CommandBar = ({
features,
operatorMode,
}: {
operatorMode: boolean;
features: string[] | null;
}) => {
const initialActions: Action[] = routesAsKbarActions(features, operatorMode);

useRegisterActions(initialActions, [operatorMode]);

return (
<KBarPortal>
<KBarPositioner
style={{ zIndex: 9999, backgroundColor: "rgb(33,33,33,0.5)" }}
>
<KBarAnimator style={animatorStyle}>
<KBarSearch style={searchStyle} />
<RenderResults />
</KBarAnimator>
</KBarPositioner>
</KBarPortal>
);
};

function RenderResults() {
const { results, rootActionId } = useMatches();

return (
<KBarResults
items={results}
onRender={({ item, active }) =>
typeof item === "string" ? (
<div style={groupNameStyle}>{item}</div>
) : (
<ResultItem
action={item}
active={active}
currentRootActionId={`${rootActionId}`}
/>
)
}
/>
);
}

const ResultItem = React.forwardRef(
(
{
action,
active,
currentRootActionId,
}: {
action: ActionImpl;
active: boolean;
currentRootActionId: ActionId;
},
ref: React.Ref<HTMLDivElement>
) => {
const classes = useStyles();
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 (
<div
ref={ref}
style={{
padding: "12px 16px",
background: active ? "#dddddd" : "transparent",
borderLeft: `2px solid ${
active ? "var(--foreground)" : "transparent"
}`,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
cursor: "pointer",
}}
>
<div className={classes.resultItem}>
{action.icon && action.icon}
<div style={{ display: "flex", flexDirection: "column" }}>
<div>
{ancestors.length > 0 &&
ancestors.map((ancestor) => (
<React.Fragment key={ancestor.id}>
<span
style={{
opacity: 0.5,
marginRight: 8,
}}
>
{ancestor.name}
</span>
<span
style={{
marginRight: 8,
}}
>
&rsaquo;
</span>
</React.Fragment>
))}
<span>{action.name}</span>
</div>
{action.subtitle && (
<span style={{ fontSize: 12 }}>{action.subtitle}</span>
)}
</div>
</div>
{action.shortcut?.length ? (
<div
aria-hidden
style={{ display: "grid", gridAutoFlow: "column", gap: "4px" }}
>
{action.shortcut.map((sc) => (
<kbd
key={sc}
style={{
padding: "4px 6px",
background: "rgba(0 0 0 / .1)",
borderRadius: "4px",
fontSize: 14,
}}
>
{sc}
</kbd>
))}
</div>
) : null}
</div>
);
}
);

export default CommandBar;

0 comments on commit 19dd7aa

Please sign in to comment.