Feat: add visual shortcuts to nodeToolbar tooltips

This commit is contained in:
igorrCarvalho 2024-06-09 18:11:34 -03:00
commit 2bbf01deaa
3 changed files with 132 additions and 33 deletions

View file

@ -0,0 +1,46 @@
import ForwardedIconComponent from "../genericIconComponent";
export default function RenderIcons({
isMac,
hasShift,
filteredShortcut,
shortcutWPlus,
}: {
isMac: boolean;
hasShift: boolean;
filteredShortcut: string[];
shortcutWPlus: string[];
}): JSX.Element {
return hasShift ? (
<>
{isMac ? (
<ForwardedIconComponent name="Command" className="h-4 w-4" />
) : (
filteredShortcut[0]
)}
<ForwardedIconComponent name="ArrowBigUp" className="ml-1 h-5 w-5" />
{filteredShortcut.map((key, idx) => {
if (idx > 0) {
return <span className="ml-1"> {key.toUpperCase()} </span>;
}
})}
</>
) : (
<>
{shortcutWPlus[0].toLowerCase() === "space" ? (
"Space"
) : shortcutWPlus[0].length <= 1 ? (
shortcutWPlus[0]
) : isMac ? (
<ForwardedIconComponent name="Command" className="h-4 w-4" />
) : (
shortcutWPlus[0]
)}
{shortcutWPlus.map((key, idx) => {
if (idx > 0) {
return <span className="ml-0.5"> {key.toUpperCase()} </span>;
}
})}
</>
);
}

View file

@ -3,7 +3,9 @@ import { useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import { useHotkeys } from "react-hotkeys-hook";
import { useUpdateNodeInternals } from "reactflow"; import { useUpdateNodeInternals } from "reactflow";
import CodeAreaComponent from "../../../../components/codeAreaComponent"; import CodeAreaComponent from "../../../../components/codeAreaComponent";
import IconComponent from "../../../../components/genericIconComponent"; import IconComponent, {
ForwardedIconComponent,
} from "../../../../components/genericIconComponent";
import ShadTooltip from "../../../../components/shadTooltipComponent"; import ShadTooltip from "../../../../components/shadTooltipComponent";
import { import {
Select, Select,
@ -32,6 +34,7 @@ import {
} from "../../../../utils/reactflowUtils"; } from "../../../../utils/reactflowUtils";
import { classNames, cn } from "../../../../utils/utils"; import { classNames, cn } from "../../../../utils/utils";
import ToolbarSelectItem from "./toolbarSelectItem"; import ToolbarSelectItem from "./toolbarSelectItem";
import RenderIcons from "../../../../components/renderIconComponent";
export default function NodeToolbarComponent({ export default function NodeToolbarComponent({
data, data,
@ -44,6 +47,7 @@ export default function NodeToolbarComponent({
setShowState, setShowState,
onCloseAdvancedModal, onCloseAdvancedModal,
}: nodeToolbarPropsType): JSX.Element { }: nodeToolbarPropsType): JSX.Element {
const isMac = navigator.platform.toUpperCase().includes("MAC");
const nodeLength = Object.keys(data.node!.template).filter( const nodeLength = Object.keys(data.node!.template).filter(
(templateField) => (templateField) =>
templateField.charAt(0) !== "_" && templateField.charAt(0) !== "_" &&
@ -57,7 +61,7 @@ export default function NodeToolbarComponent({
data.node.template[templateField].type === "Any" || data.node.template[templateField].type === "Any" ||
data.node.template[templateField].type === "int" || data.node.template[templateField].type === "int" ||
data.node.template[templateField].type === "dict" || data.node.template[templateField].type === "dict" ||
data.node.template[templateField].type === "NestedDict") data.node.template[templateField].type === "NestedDict"),
).length; ).length;
const hasStore = useStoreStore((state) => state.hasStore); const hasStore = useStoreStore((state) => state.hasStore);
@ -196,7 +200,7 @@ export default function NodeToolbarComponent({
const [showconfirmShare, setShowconfirmShare] = useState(false); const [showconfirmShare, setShowconfirmShare] = useState(false);
const [showOverrideModal, setShowOverrideModal] = useState(false); const [showOverrideModal, setShowOverrideModal] = useState(false);
const [flowComponent, setFlowComponent] = useState<FlowType>( const [flowComponent, setFlowComponent] = useState<FlowType>(
createFlowComponent(cloneDeep(data), version) createFlowComponent(cloneDeep(data), version),
); );
// useEffect(() => { // useEffect(() => {
@ -215,7 +219,7 @@ export default function NodeToolbarComponent({
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const setLastCopiedSelection = useFlowStore( const setLastCopiedSelection = useFlowStore(
(state) => state.setLastCopiedSelection (state) => state.setLastCopiedSelection,
); );
const setSuccessData = useAlertStore((state) => state.setSuccessData); const setSuccessData = useAlertStore((state) => state.setSuccessData);
@ -289,7 +293,7 @@ export default function NodeToolbarComponent({
nodes, nodes,
edges, edges,
setNodes, setNodes,
setEdges setEdges,
); );
break; break;
case "override": case "override":
@ -313,20 +317,56 @@ export default function NodeToolbarComponent({
y: 10, y: 10,
paneX: nodes.find((node) => node.id === data.id)?.position.x, paneX: nodes.find((node) => node.id === data.id)?.position.x,
paneY: nodes.find((node) => node.id === data.id)?.position.y, paneY: nodes.find((node) => node.id === data.id)?.position.y,
} },
); );
break; break;
} }
}; };
const isSaved = flows.some((flow) => const isSaved = flows.some((flow) =>
Object.values(flow).includes(data.node?.display_name!) Object.values(flow).includes(data.node?.display_name!),
); );
function displayShortcut({
name,
shortcut,
}: {
name: string;
shortcut: string;
}): JSX.Element {
let hasShift: boolean = false;
const fixedShortcut = shortcut?.split("+");
fixedShortcut.forEach((key) => {
if (key.toLowerCase().includes("shift")) {
hasShift = true;
}
});
const filteredShortcut = fixedShortcut.filter(
(key) => !key.toLowerCase().includes("shift"),
);
let shortcutWPlus: string[] = [];
if (!hasShift) shortcutWPlus = filteredShortcut.join("+").split(" ");
return (
<div className="flex justify-center">
<span> {name} </span>
<span
className={`ml-3 flex items-center rounded-sm bg-muted px-1 py-[0.2] text-muted-foreground`}
>
<RenderIcons
isMac={isMac}
hasShift={hasShift}
filteredShortcut={filteredShortcut}
shortcutWPlus={shortcutWPlus}
/>
</span>
</div>
);
}
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
const handleOnNewValue = ( const handleOnNewValue = (
newValue: string | string[] | boolean | Object[] newValue: string | string[] | boolean | Object[],
): void => { ): void => {
if (data.node!.template[name].value !== newValue) { if (data.node!.template[name].value !== newValue) {
takeSnapshot(); takeSnapshot();
@ -378,7 +418,14 @@ export default function NodeToolbarComponent({
<div className="w-26 nocopy nowheel nopan nodelete nodrag noundo h-10"> <div className="w-26 nocopy nowheel nopan nodelete nodrag noundo h-10">
<span className="isolate inline-flex rounded-md shadow-sm"> <span className="isolate inline-flex rounded-md shadow-sm">
{hasCode && ( {hasCode && (
<ShadTooltip content="Code" side="top"> <ShadTooltip
content={displayShortcut(
shortcuts.find(
({ name }) => name.split(" ")[0].toLowerCase() === "code",
)!,
)}
side="top"
>
<button <button
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
onClick={() => { onClick={() => {
@ -391,7 +438,14 @@ export default function NodeToolbarComponent({
</ShadTooltip> </ShadTooltip>
)} )}
{nodeLength > 0 && ( {nodeLength > 0 && (
<ShadTooltip content="Advanced Settings" side="top"> <ShadTooltip
content={displayShortcut(
shortcuts.find(
({ name }) => name.split(" ")[0].toLowerCase() === "advanced",
)!,
)}
side="top"
>
<button <button
className="relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" className="relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
onClick={() => { onClick={() => {
@ -422,10 +476,17 @@ export default function NodeToolbarComponent({
<IconComponent name="SaveAll" className="h-4 w-4" /> <IconComponent name="SaveAll" className="h-4 w-4" />
</button> </button>
</ShadTooltip>*/} </ShadTooltip>*/}
<ShadTooltip content="Freeze" side="top"> <ShadTooltip
content={displayShortcut(
shortcuts.find(
({ name }) => name.split(" ")[0].toLowerCase() === "freeze",
)!,
)}
side="top"
>
<button <button
className={classNames( className={classNames(
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" "relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
)} )}
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
@ -446,7 +507,7 @@ export default function NodeToolbarComponent({
className={cn( className={cn(
"h-4 w-4 transition-all", "h-4 w-4 transition-all",
// TODO UPDATE THIS COLOR TO BE A VARIABLE // TODO UPDATE THIS COLOR TO BE A VARIABLE
frozen ? "animate-wiggle text-ice" : "" frozen ? "animate-wiggle text-ice" : "",
)} )}
/> />
</button> </button>
@ -468,13 +529,13 @@ export default function NodeToolbarComponent({
</ShadTooltip>*/} </ShadTooltip>*/}
<Select onValueChange={handleSelectChange} value=""> <Select onValueChange={handleSelectChange} value="">
<ShadTooltip content="More" side="top"> <ShadTooltip content="All" side="top">
<SelectTrigger> <SelectTrigger>
<div> <div>
<div <div
data-testid="more-options-modal" data-testid="more-options-modal"
className={classNames( className={classNames(
"relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" "relative -ml-px inline-flex h-8 w-[31px] items-center rounded-r-md bg-background text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10",
)} )}
> >
<IconComponent <IconComponent

View file

@ -1,4 +1,5 @@
import ForwardedIconComponent from "../../../../../components/genericIconComponent"; import ForwardedIconComponent from "../../../../../components/genericIconComponent";
import RenderIcons from "../../../../../components/renderIconComponent";
import { toolbarSelectItemProps } from "../../../../../types/components"; import { toolbarSelectItemProps } from "../../../../../types/components";
export default function ToolbarSelectItem({ export default function ToolbarSelectItem({
@ -9,6 +10,7 @@ export default function ToolbarSelectItem({
ping, ping,
shortcut, shortcut,
}: toolbarSelectItemProps) { }: toolbarSelectItemProps) {
const isMac = navigator.platform.toUpperCase().includes("MAC");
let hasShift = false; let hasShift = false;
const fixedShortcut = shortcut?.split("+"); const fixedShortcut = shortcut?.split("+");
fixedShortcut.forEach((key) => { fixedShortcut.forEach((key) => {
@ -19,8 +21,8 @@ export default function ToolbarSelectItem({
const filteredShortcut = fixedShortcut.filter( const filteredShortcut = fixedShortcut.filter(
(key) => !key.toLowerCase().includes("shift"), (key) => !key.toLowerCase().includes("shift"),
); );
let shortcutWPlus = ""; let shortcutWPlus: string[] = [];
if (!hasShift) shortcutWPlus = filteredShortcut.join("+"); if (!hasShift) shortcutWPlus = filteredShortcut.join("+").split(" ");
return ( return (
<div className={`flex ${style}`} data-testid={dataTestId}> <div className={`flex ${style}`} data-testid={dataTestId}>
@ -34,22 +36,12 @@ export default function ToolbarSelectItem({
{value} {value}
</span> </span>
<span className={`absolute right-2 top-[0.43em] flex `}> <span className={`absolute right-2 top-[0.43em] flex `}>
{hasShift ? ( <RenderIcons
<> isMac={isMac}
{filteredShortcut[0]} hasShift={hasShift}
<ForwardedIconComponent filteredShortcut={filteredShortcut}
name="ArrowBigUp" shortcutWPlus={shortcutWPlus}
className="ml-1 h-5 w-5" />
/>
{filteredShortcut.map((key, idx) => {
if (idx > 0) {
return <span className="ml-1"> {key.toUpperCase()} </span>;
}
})}
</>
) : (
shortcutWPlus
)}
</span> </span>
</div> </div>
); );