feat(builder): Standardize icons and integrate with ControlPanel and NavBar (#7743)

* feat(builder): Add new icons and integrate with ControlPanel

Introduce SVG icons and replace ControlPanel dependencies with new icons. The ControlPanel component now uses the new icon components for improved consistency.

* feat(builder): add additional icon and update icons in NavBar

Introduced the new icon with relevant documentation and examples. Replaced existing icon imports with the newly defined icons in the NavBar component for consistency.

* feat(builder): Add icon for megaphone and replace usage

Introduced the IconMegaphone for reuse across the application. Updated TallyPopup to utilize IconMegaphone instead of the previous Megaphone icon from lucide-react.

* fix(builder): Running prettier to format changed files.

Adjusted various files for consistent code formatting. Ensured proper spacing and alignment of imports, JSX tags, and object properties to enhance readability and maintain coding standards. No functional changes made.
This commit is contained in:
Andy Hooker
2024-08-08 03:55:57 -05:00
committed by GitHub
parent 8131fc385b
commit 3cad0f89ee
8 changed files with 531 additions and 120 deletions

View File

@@ -27,7 +27,6 @@ import AutoGPTServerAPI, {
Graph,
NodeExecutionResult,
} from "@/lib/autogpt-server-api";
import { Play, Undo2, Redo2 } from "lucide-react";
import {
deepEquals,
getTypeColor,
@@ -41,6 +40,7 @@ import Ajv from "ajv";
import { Control, ControlPanel } from "@/components/edit/control/ControlPanel";
import { SaveControl } from "@/components/edit/control/SaveControl";
import { BlocksControl } from "@/components/edit/control/BlocksControl";
import { IconPlay, IconRedo2, IconUndo2 } from "@/components/ui/icons";
// This is for the history, this is the minimum distance a block must move before it is logged
// It helps to prevent spamming the history with small movements especially when pressing on a input in a block
@@ -843,17 +843,17 @@ const FlowEditor: React.FC<{
const editorControls: Control[] = [
{
label: "Undo",
icon: <Undo2 size={18} />,
icon: <IconUndo2 />,
onClick: handleUndo,
},
{
label: "Redo",
icon: <Redo2 size={18} />,
icon: <IconRedo2 />,
onClick: handleRedo,
},
{
label: "Run",
icon: <Play size={18} />,
icon: <IconPlay />,
onClick: runAgent,
},
];

View File

@@ -1,19 +1,17 @@
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import Link from "next/link";
import { CircleUser, Menu, SquareActivity, Workflow } from "lucide-react";
import { Button, buttonVariants } from "@/components/ui/button";
import { Button } from "@/components/ui/button";
import React from "react";
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet";
import { Pencil1Icon, TimerIcon, ArchiveIcon } from "@radix-ui/react-icons";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import Image from "next/image";
import getServerUser from "@/hooks/getServerUser";
import ProfileDropdown from "./ProfileDropdown";
import {
IconCircleUser,
IconMenu,
IconPackage2,
IconSquareActivity,
IconWorkFlow,
} from "@/components/ui/icons";
export async function NavBar() {
const isAvailable = Boolean(
@@ -32,7 +30,7 @@ export async function NavBar() {
size="icon"
className="shrink-0 md:hidden"
>
<Menu className="size-5" />
<IconMenu />
<span className="sr-only">Toggle navigation menu</span>
</Button>
</SheetTrigger>
@@ -42,19 +40,19 @@ export async function NavBar() {
href="/monitor"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2 "
>
<SquareActivity className="size-6" /> Monitor
<IconSquareActivity /> Monitor
</Link>
<Link
href="/build"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2"
>
<Workflow className="size-6" /> Build
<IconWorkFlow /> Build
</Link>
<Link
href="/marketplace"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2"
>
<ArchiveIcon className="size-6" /> Marketplace
<IconPackage2 /> Marketplace
</Link>
</nav>
</SheetContent>
@@ -64,19 +62,19 @@ export async function NavBar() {
href="/monitor"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2 items-center"
>
<SquareActivity className="size-4" /> Monitor
<IconSquareActivity /> Monitor
</Link>
<Link
href="/build"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2 items-center"
>
<Workflow className="size-4" /> Build
<IconWorkFlow /> Build
</Link>
<Link
href="/marketplace"
className="text-muted-foreground hover:text-foreground flex flex-row gap-2 items-center"
>
<ArchiveIcon className="size-4" /> Marketplace
<IconPackage2 /> Marketplace
</Link>
</nav>
</div>
@@ -104,7 +102,7 @@ export async function NavBar() {
className="text-muted-foreground hover:text-foreground flex flex-row gap-2 items-center"
>
Log In
<CircleUser className="size-5" />
<IconCircleUser />
</Link>
)}
{isAvailable && user && <ProfileDropdown />}

View File

@@ -1,7 +1,7 @@
"use client";
import React, { useEffect, useState } from "react";
import { Button } from "./ui/button";
import { Megaphone } from "lucide-react";
import { IconMegaphone } from "@/components/ui/icons";
const TallyPopupSimple = () => {
const [isFormVisible, setIsFormVisible] = useState(false);
@@ -49,7 +49,7 @@ const TallyPopupSimple = () => {
data-tally-emoji-text="👋"
data-tally-emoji-animation="wave"
>
<Megaphone />
<IconMegaphone size="lg" />
<span className="sr-only">Reach Out</span>
</Button>
</div>

View File

@@ -1,65 +0,0 @@
import { Card, CardContent } from "@/components/ui/card";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import React from "react";
/**
* Represents a control element for the ControlPanel Component.
* @type {Object} Control
* @property {React.ReactNode} icon - The icon of the control from lucide-react https://lucide.dev/icons/
* @property {string} label - The label of the control, to be leveraged by ToolTip.
* @property {onclick} onClick - The function to be executed when the control is clicked.
*/
export type Control = {
icon: React.ReactNode;
label: string;
onClick: () => void;
};
interface ControlPanelProps {
controls: Control[];
children?: React.ReactNode;
}
/**
* ControlPanel component displays a panel with controls as icons with the ability to take in children.
* @param {Object} ControlPanelProps - The properties of the control panel component.
* @param {Array} ControlPanelProps.controls - An array of control objects representing actions to be preformed.
* @param {Array} ControlPanelProps.children - The child components of the control panel.
* @returns The rendered control panel component.
*/
export const ControlPanel = ({ controls, children }: ControlPanelProps) => {
return (
<aside className="hidden w-14 flex-col sm:flex">
<Card>
<CardContent className="p-0">
<div className="flex flex-col items-center gap-4 px-2 sm:py-5 rounded-radius">
{controls.map((control, index) => (
<Tooltip key={index} delayDuration={500}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => control.onClick()}
>
{control.icon}
<span className="sr-only">{control.label}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="right">{control.label}</TooltipContent>
</Tooltip>
))}
<Separator />
{children}
</div>
</CardContent>
</Card>
</aside>
);
};
export default ControlPanel;

View File

@@ -13,6 +13,7 @@ import {
} from "@/components/ui/popover";
import { Block } from "@/lib/autogpt-server-api";
import { PlusIcon } from "@radix-ui/react-icons";
import { IconToyBrick } from "@/components/ui/icons";
interface BlocksControlProps {
blocks: Block[];
@@ -41,13 +42,13 @@ export const BlocksControl: React.FC<BlocksControlProps> = ({
return (
<Popover>
<PopoverTrigger asChild>
<Button size="icon" variant="ghost">
<ToyBrick size={18} />
<Button variant="ghost" size="icon">
<IconToyBrick />
</Button>
</PopoverTrigger>
<PopoverContent
side="right"
sideOffset={15}
sideOffset={22}
align="start"
className="w-80 p-0"
>

View File

@@ -29,7 +29,7 @@ interface ControlPanelProps {
}
/**
* ControlPanel component displays a panel with controls as icons with the ability to take in children.
* ControlPanel component displays a panel with controls as icons.tsx with the ability to take in children.
* @param {Object} ControlPanelProps - The properties of the control panel component.
* @param {Array} ControlPanelProps.controls - An array of control objects representing actions to be preformed.
* @param {Array} ControlPanelProps.children - The child components of the control panel.
@@ -42,31 +42,29 @@ export const ControlPanel = ({
className,
}: ControlPanelProps) => {
return (
<aside className={cn("hidden w-14 flex-col sm:flex", className)}>
<Card>
<CardContent className="p-0">
<div className="flex flex-col items-center gap-4 px-2 sm:py-5 rounded-radius">
{children}
<Separator />
{controls.map((control, index) => (
<Tooltip key={index} delayDuration={500}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => control.onClick()}
>
{control.icon}
<span className="sr-only">{control.label}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="right">{control.label}</TooltipContent>
</Tooltip>
))}
</div>
</CardContent>
</Card>
</aside>
<Card className={cn("w-14", className)}>
<CardContent className="p-0">
<div className="flex flex-col items-center gap-8 px-2 sm:py-5 rounded-radius">
{children}
<Separator />
{controls.map((control, index) => (
<Tooltip key={index} delayDuration={500}>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => control.onClick()}
>
{control.icon}
<span className="sr-only">{control.label}</span>
</Button>
</TooltipTrigger>
<TooltipContent side="right">{control.label}</TooltipContent>
</Tooltip>
))}
</div>
</CardContent>
</Card>
);
};
export default ControlPanel;

View File

@@ -9,7 +9,7 @@ import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { GraphMeta } from "@/lib/autogpt-server-api";
import { Label } from "@/components/ui/label";
import { Save } from "lucide-react";
import { IconSave } from "@/components/ui/icons";
interface SaveControlProps {
agentMeta: GraphMeta | null;
@@ -53,7 +53,7 @@ export const SaveControl = ({
<Popover>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon">
<Save size={18} />
<IconSave />
</Button>
</PopoverTrigger>
<PopoverContent side="right" sideOffset={15} align="start">

View File

@@ -0,0 +1,479 @@
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
/**
* Represents different variants of an icon, based on its size.
*/
const iconVariants = {
size: {
default: "size-4",
sm: "size-2",
lg: "size-6",
},
} as const;
/**
* Props for the Icon component.
*/
export interface IconProps extends React.SVGProps<SVGSVGElement> {
size?: keyof typeof iconVariants.size;
}
/**
* Creates an icon component that wraps a given SVG icon component.
* This function applies consistent styling and size variants to the icon.
*
* @template P - The props type for the icon component
* @param {React.FC<P>} IconComponent - The SVG icon component to be wrapped
* @returns {React.ForwardRefExoticComponent<IconProps & React.RefAttributes<SVGSVGElement>>}
*
*/
const createIcon = <P extends React.SVGProps<SVGSVGElement>>(
IconComponent: React.FC<P>,
): React.ForwardRefExoticComponent<
IconProps & React.RefAttributes<SVGSVGElement>
> => {
const Icon = React.forwardRef<SVGSVGElement, IconProps>(
({ className, size = "default", ...props }, ref) => {
return (
<IconComponent
className={cn(iconVariants.size[size], className)}
ref={ref}
{...(props as P)}
/>
);
},
);
Icon.displayName = IconComponent.name || "Icon";
return Icon;
};
/**
* Save icon component.
*
* @component IconSave
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The save icon.
*
* @example
* // Default usage this is the standard usage
* <IconSave />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconSave className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconSave size="sm" onClick={handleOnClick} />
*/
export const IconSave = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" />
<path d="M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" />
<path d="M7 3v4a1 1 0 0 0 1 1h7" />
</svg>
));
/**
* Undo icon component.
*
* @component IconUndo2
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The undo icon.
*
* @example
* // Default usage this is the standard usage
* <IconUndo2 />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconUndo2 className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconUndo2 size="sm" onClick={handleOnClick} />
*/
export const IconUndo2 = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M9 14 4 9l5-5" />
<path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11" />
</svg>
));
/**
* Redo icon component.
*
* @component IconRedo2
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The redo icon.
*
* @example
* // Default usage this is the standard usage
* <IconRedo2 />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconRedo2 className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconRedo2 size="sm" onClick={handleOnClick} />
*/
export const IconRedo2 = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="m15 14 5-5-5-5" />
<path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5A5.5 5.5 0 0 0 9.5 20H13" />
</svg>
));
/**
* Toy brick icon component.
*
* @component IconToyBrick
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The toy brick icon.
*
* @example
* // Default usage this is the standard usage
* <IconToyBrick />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconToyBrick className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconToyBrick size="sm" onClick={handleOnClick} />
*/
export const IconToyBrick = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<rect width="18" height="12" x="3" y="8" rx="1" />
<path d="M10 8V5c0-.6-.4-1-1-1H6a1 1 0 0 0-1 1v3" />
<path d="M19 8V5c0-.6-.4-1-1-1h-3a1 1 0 0 0-1 1v3" />
</svg>
));
/**
* A circle alert icon component.
*
* @component IconCircleAlert
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The circle alert icon.
*
* @example
* // Default usage this is the standard usage
* <IconCircleAlert />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconCircleAlert className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconCircleAlert size="sm" onClick={handleOnClick} />
*/
export const IconCircleAlert = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<circle cx="12" cy="12" r="10" />
<line x1="12" x2="12" y1="8" y2="12" />
<line x1="12" x2="12.01" y1="16" y2="16" />
</svg>
));
/**
* Circle User icon component.
*
* @component IconCircleUser
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The circle user icon.
*
* @example
* // Default usage this is the standard usage
* <IconCircleUser />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconCircleUser className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconCircleUser size="sm" onClick={handleOnClick} />
*/
export const IconCircleUser = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<circle cx="12" cy="12" r="10" />
<circle cx="12" cy="10" r="3" />
<path d="M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662" />
</svg>
));
/**
* Menu icon component.
*
* @component IconMenu
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The menu icon.
*
* @example
* // Default usage this is the standard usage
* <IconMenu />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconMenu className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconMenu size="sm" onClick={handleOnClick} />
*/
export const IconMenu = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<line x1="4" x2="20" y1="12" y2="12" />
<line x1="4" x2="20" y1="6" y2="6" />
<line x1="4" x2="20" y1="18" y2="18" />
</svg>
));
/**
* Square Activity icon component.
*
* @component IconSquareActivity
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The square activity icon.
*
* @example
* // Default usage this is the standard usage
* <IconSquareActivity />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconSquareActivity className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconSquareActivity size="sm" onClick={handleOnClick} />
*/
export const IconSquareActivity = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<rect width="18" height="18" x="3" y="3" rx="2" />
<path d="M17 12h-2l-2 5-2-10-2 5H7" />
</svg>
));
/**
* Workflow icon component.
*
* @component IconWorkFlow
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The workflow icon.
*
* @example
* // Default usage this is the standard usage
* <IconWorkFlow />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconWorkFlow className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconWorkFlow size="sm" onClick={handleOnClick} />
*/
export const IconWorkFlow = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<rect width="8" height="8" x="3" y="3" rx="2" />
<path d="M7 11v4a2 2 0 0 0 2 2h4" />
<rect width="8" height="8" x="13" y="13" rx="2" />
</svg>
));
/**
* Play icon component.
*
* @component IconPlay
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The play icon.
*
* @example
* // Default usage this is the standard usage
* <IconPlay />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconPlay className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconPlay size="sm" onClick={handleOnClick} />
*/
export const IconPlay = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<polygon points="6 3 20 12 6 21 6 3" />
</svg>
));
/**
* Package2 icon component.
*
* @component IconPackage2
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The package2 icon.
*
* @example
* // Default usage this is the standard usage
* <IconPackage2 />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconPackage2 className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconPackage2 size="sm" onClick={handleOnClick} />
*/
export const IconPackage2 = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="M3 9h18v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9Z" />
<path d="m3 9 2.45-4.9A2 2 0 0 1 7.24 3h9.52a2 2 0 0 1 1.8 1.1L21 9" />
<path d="M12 3v6" />
</svg>
));
/**
* Megaphone icon component.
*
* @component IconMegaphone
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
* @returns {JSX.Element} - The megaphone icon.
*
* @example
* // Default usage this is the standard usage
* <IconMegaphone />
*
* @example
* // With custom color and size these should be used sparingly and only when necessary
* <IconMegaphone className="text-primary" size="lg" />
*
* @example
* // With custom size and onClick handler
* <IconMegaphone size="sm" onClick={handleOnClick} />
*/
export const IconMegaphone = createIcon((props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
{...props}
>
<path d="m3 11 18-5v12L3 14v-3z" />
<path d="M11.6 16.8a3 3 0 1 1-5.8-1.6" />
</svg>
));
export { iconVariants };