fix: sidebar animations, colors and minor design fixes (#4379)

This commit is contained in:
Lucas Oliveira 2024-11-05 13:15:04 -03:00 • committed by GitHub
commit 91b650fd03
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 323 additions and 352 deletions

View file

@ -79,7 +79,7 @@ export default function FlowToolbar(): JSX.Element {
<button <button
disabled={!hasApiKey || !validApiKey || !hasStore} disabled={!hasApiKey || !validApiKey || !hasStore}
className={classNames( className={classNames(
"share-button", "relative inline-flex h-8 w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-accent",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? "text-muted-foreground" ? "text-muted-foreground"
: "", : "",
@ -93,13 +93,13 @@ export default function FlowToolbar(): JSX.Element {
<ForwardedIconComponent <ForwardedIconComponent
name="Share2" name="Share2"
className={classNames( className={classNames(
"-m-0.5 -ml-1 h-4 w-4", "h-4 w-4",
!hasApiKey || !validApiKey || !hasStore !hasApiKey || !validApiKey || !hasStore
? "extra-side-bar-save-disable" ? "extra-side-bar-save-disable"
: "", : "",
)} )}
/> />
Share <span className="hidden md:block">Share</span>
</> </>
</button> </button>
</ShadTooltip> </ShadTooltip>
@ -134,26 +134,26 @@ export default function FlowToolbar(): JSX.Element {
> >
<div <div
data-testid="playground-btn-flow-io" data-testid="playground-btn-flow-io"
className="relative inline-flex w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold transition-all duration-500 ease-in-out hover:bg-accent" className="relative inline-flex h-8 w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold transition-all duration-500 ease-in-out hover:bg-accent"
> >
<ForwardedIconComponent <ForwardedIconComponent
name="Play" name="Play"
className={"h-4 w-4 transition-all"} className={"h-4 w-4 transition-all"}
/> />
Playground <span className="hidden md:block">Playground</span>
</div> </div>
</IOModal> </IOModal>
) : ( ) : (
<ShadTooltip content="Add a Chat Input or Chat Output to use the playground"> <ShadTooltip content="Add a Chat Input or Chat Output to use the playground">
<div <div
className={`relative inline-flex w-full cursor-not-allowed items-center justify-center gap-1 px-5 py-3 text-sm font-semibold text-muted-foreground transition-all duration-150 ease-in-out`} className={`relative inline-flex h-8 w-full cursor-not-allowed items-center justify-center gap-1 px-5 py-3 text-sm font-semibold text-muted-foreground transition-all duration-150 ease-in-out`}
data-testid="playground-btn-flow" data-testid="playground-btn-flow"
> >
<ForwardedIconComponent <ForwardedIconComponent
name="BotMessageSquareIcon" name="BotMessageSquareIcon"
className={"h-5 w-5 transition-all"} className={"h-5 w-5 transition-all"}
/> />
Playground <span className="hidden md:block">Playground</span>
</div> </div>
</ShadTooltip> </ShadTooltip>
)} )}
@ -169,14 +169,14 @@ export default function FlowToolbar(): JSX.Element {
> >
<div <div
className={classNames( className={classNames(
"relative inline-flex w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-accent", "relative inline-flex h-8 w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-accent",
)} )}
> >
<ForwardedIconComponent <ForwardedIconComponent
name="Code2" name="Code2"
className={"h-4 w-4"} className={"h-4 w-4"}
/> />
API <span className="hidden md:block">API</span>
</div> </div>
</ApiModal> </ApiModal>
)} )}

View file

@ -1,4 +1,3 @@
import { IS_MAC } from "@/constants/constants";
import { addPlusSignes, cn, sortShortcuts } from "@/utils/utils"; import { addPlusSignes, cn, sortShortcuts } from "@/utils/utils";
import RenderKey from "./components/renderKey"; import RenderKey from "./components/renderKey";

View file

@ -15,8 +15,8 @@ const badgeVariants = cva(
destructive: destructive:
"bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground", "bg-destructive hover:bg-destructive/80 border-transparent text-destructive-foreground",
outline: "text-primary/80 border-ring/60", outline: "text-primary/80 border-ring/60",
secondaryStatic: "bg-input text-muted-foreground", secondaryStatic: "bg-input text-muted-foreground border-0",
pinkStatic: "bg-accent-pink text-accent-pink-foreground", pinkStatic: "bg-accent-pink text-accent-pink-foreground border-0",
}, },
size: { size: {
sm: "h-4 text-xs", sm: "h-4 text-xs",

View file

@ -5,12 +5,10 @@ import { VariantProps, cva } from "class-variance-authority";
import { PanelLeft } from "lucide-react"; import { PanelLeft } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { useIsMobile } from "../../hooks/use-mobile";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import { Button } from "./button"; import { Button } from "./button";
import { Input } from "./input"; import { Input } from "./input";
import { Separator } from "./separator"; import { Separator } from "./separator";
import { Sheet, SheetContent } from "./sheet";
import { Skeleton } from "./skeleton"; import { Skeleton } from "./skeleton";
import { import {
Tooltip, Tooltip,
@ -22,17 +20,13 @@ import {
const SIDEBAR_COOKIE_NAME = "sidebar:state"; const SIDEBAR_COOKIE_NAME = "sidebar:state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
const SIDEBAR_WIDTH = "19rem"; const SIDEBAR_WIDTH = "19rem";
const SIDEBAR_WIDTH_MOBILE = "18rem"; const SIDEBAR_WIDTH_ICON = "4rem";
const SIDEBAR_WIDTH_ICON = "3rem";
const SIDEBAR_KEYBOARD_SHORTCUT = "b"; const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContext = { type SidebarContext = {
state: "expanded" | "collapsed"; state: "expanded" | "collapsed";
open: boolean; open: boolean;
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void;
openMobile: boolean;
setOpenMobile: (open: boolean) => void;
isMobile: boolean;
toggleSidebar: () => void; toggleSidebar: () => void;
}; };
@ -53,6 +47,7 @@ const SidebarProvider = React.forwardRef<
defaultOpen?: boolean; defaultOpen?: boolean;
open?: boolean; open?: boolean;
onOpenChange?: (open: boolean) => void; onOpenChange?: (open: boolean) => void;
width?: string;
} }
>( >(
( (
@ -63,13 +58,11 @@ const SidebarProvider = React.forwardRef<
className, className,
style, style,
children, children,
width = SIDEBAR_WIDTH,
...props ...props
}, },
ref, ref,
) => { ) => {
const isMobile = useIsMobile();
const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar. // This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component. // We use openProp and setOpenProp for control from outside the component.
const [_open, _setOpen] = React.useState(defaultOpen); const [_open, _setOpen] = React.useState(defaultOpen);
@ -92,10 +85,8 @@ const SidebarProvider = React.forwardRef<
// Helper to toggle the sidebar. // Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => { const toggleSidebar = React.useCallback(() => {
return isMobile return setOpen((open) => !open);
? setOpenMobile((open) => !open) }, [setOpen]);
: setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar. // Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => { React.useEffect(() => {
@ -122,20 +113,9 @@ const SidebarProvider = React.forwardRef<
state, state,
open, open,
setOpen, setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar, toggleSidebar,
}), }),
[ [state, open, setOpen, toggleSidebar],
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
],
); );
return ( return (
@ -144,7 +124,7 @@ const SidebarProvider = React.forwardRef<
<div <div
style={ style={
{ {
"--sidebar-width": SIDEBAR_WIDTH, "--sidebar-width": width,
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON, "--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
...style, ...style,
} as React.CSSProperties } as React.CSSProperties
@ -184,47 +164,33 @@ const Sidebar = React.forwardRef<
}, },
ref, ref,
) => { ) => {
const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); const { state } = useSidebar();
if (collapsible === "none") { if (collapsible === "none") {
return ( return (
<div <div
className={cn( className={cn(
"flex h-full w-[--sidebar-width] flex-col bg-background text-foreground", "group flex h-full w-[--sidebar-width] flex-col bg-background text-foreground",
className, className,
)} )}
data-side={side}
ref={ref} ref={ref}
{...props} {...props}
> >
{children} <div
</div>
);
}
if (isMobile) {
return (
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
<SheetContent
data-sidebar="sidebar" data-sidebar="sidebar"
data-mobile="true" className="flex h-full w-full flex-col group-data-[side=left]:border-r group-data-[side=right]:border-l"
className="w-[--sidebar-width] bg-background p-0 text-foreground [&>button]:hidden"
style={
{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
}
side={side}
> >
<div className="flex h-full w-full flex-col">{children}</div> {children}
</SheetContent> </div>
</Sheet> </div>
); );
} }
return ( return (
<div <div
ref={ref} ref={ref}
className="group peer relative flex h-full flex-col md:block" className="group peer relative block h-full flex-col"
data-state={state} data-state={state}
data-collapsible={state === "collapsed" ? collapsible : ""} data-collapsible={state === "collapsed" ? collapsible : ""}
data-variant={variant} data-variant={variant}
@ -239,11 +205,18 @@ const Sidebar = React.forwardRef<
variant === "floating" || variant === "inset" variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]" ? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon]", : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
// Keep icon width on mobile when collapsed
collapsible === "icon"
? "max-sm:w-[--sidebar-width-icon]"
: "max-sm:w-0",
)} )}
/> />
<div <div
className={cn( className={cn(
"absolute inset-y-0 z-10 hidden h-full w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex", "absolute inset-y-0 z-50 flex h-full transition-[left,right,width] duration-200 ease-linear",
// Adjust width based on state and device
"w-[--sidebar-width]",
"max-sm:group-data-[state=collapsed]:w-[--sidebar-width-icon]",
side === "left" side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]" ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]", : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
@ -251,13 +224,20 @@ const Sidebar = React.forwardRef<
variant === "floating" || variant === "inset" variant === "floating" || variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]" ? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l", : "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",
// Position absolute relative to parent container on mobile
"max-sm:absolute max-sm:h-[100%] max-sm:group-data-[state=expanded]:bg-background/80",
className, className,
)} )}
{...props} {...props}
> >
<div <div
data-sidebar="sidebar" data-sidebar="sidebar"
className="flex h-full w-full flex-col bg-background group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-border group-data-[variant=floating]:shadow" className={cn(
"flex h-full w-full flex-col bg-background",
"group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-border group-data-[variant=floating]:shadow",
// Add shadow on mobile
"max-sm:shadow-lg",
)}
> >
{children} {children}
</div> </div>
@ -280,15 +260,21 @@ const SidebarTrigger = React.forwardRef<
data-sidebar="trigger" data-sidebar="trigger"
variant="ghost" variant="ghost"
size="icon" size="icon"
className={cn("h-7 w-7", className)} className={cn("h-8 w-8", className)}
onClick={(event) => { onClick={(event) => {
onClick?.(event); onClick?.(event);
toggleSidebar(); toggleSidebar();
}} }}
{...props} {...props}
> >
<PanelLeft /> {props.children ? (
<span className="sr-only">Toggle Sidebar</span> props.children
) : (
<>
<PanelLeft />
<span className="sr-only">Toggle Sidebar</span>
</>
)}
</Button> </Button>
); );
}); });
@ -332,7 +318,7 @@ const SidebarInset = React.forwardRef<
ref={ref} ref={ref}
className={cn( className={cn(
"relative flex min-h-svh flex-1 flex-col bg-background", "relative flex min-h-svh flex-1 flex-col bg-background",
"peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow", "peer-data-[variant=inset]:m-2 peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 peer-data-[variant=inset]:ml-0 peer-data-[variant=inset]:rounded-xl peer-data-[variant=inset]:shadow",
className, className,
)} )}
{...props} {...props}
@ -350,7 +336,7 @@ const SidebarInput = React.forwardRef<
ref={ref} ref={ref}
data-sidebar="input" data-sidebar="input"
className={cn( className={cn(
"h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-ring", "h-8 w-full bg-background shadow-none focus-visible:ring-1 focus-visible:ring-ring",
className, className,
)} )}
{...props} {...props}
@ -448,7 +434,7 @@ const SidebarGroupLabel = React.forwardRef<
ref={ref} ref={ref}
data-sidebar="group-label" data-sidebar="group-label"
className={cn( className={cn(
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-semibold text-foreground/70 outline-none ring-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-semibold text-foreground/70 outline-none ring-ring transition-[margin,opa] duration-200 ease-linear focus-visible:ring-1 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0", "group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className, className,
)} )}
@ -469,9 +455,9 @@ const SidebarGroupAction = React.forwardRef<
ref={ref} ref={ref}
data-sidebar="group-action" data-sidebar="group-action"
className={cn( className={cn(
"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-foreground outline-none ring-ring transition-transform hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-foreground outline-none ring-ring transition-transform hover:bg-accent hover:text-accent-foreground focus-visible:ring-1 [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile. // Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden", "after:-inset-2 after:hidden",
"group-data-[collapsible=icon]:hidden", "group-data-[collapsible=icon]:hidden",
className, className,
)} )}
@ -521,11 +507,12 @@ const SidebarMenuItem = React.forwardRef<
SidebarMenuItem.displayName = "SidebarMenuItem"; SidebarMenuItem.displayName = "SidebarMenuItem";
const sidebarMenuButtonVariants = cva( const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-ring transition-[width,height,padding] hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 active:bg-accent active:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-accent data-[active=true]:font-medium data-[active=true]:text-accent-foreground data-[state=open]:hover:bg-accent data-[state=open]:hover:text-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0", "peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-ring transition-[width,height,padding] hover:bg-accent hover:text-accent-foreground focus-visible:ring-1 active:bg-accent active:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-accent data-[active=true]:font-medium data-[active=true]:text-accent-foreground data-[state=open]:hover:bg-accent data-[state=open]:hover:text-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
{ {
variants: { variants: {
variant: { variant: {
default: "hover:bg-accent hover:text-accent-foreground", default:
"text-secondary-foreground hover:bg-accent hover:text-accent-foreground ",
outline: outline:
"bg-background shadow-[0_0_0_1px_hsl(var(--border))] hover:bg-accent hover:text-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--accent))]", "bg-background shadow-[0_0_0_1px_hsl(var(--border))] hover:bg-accent hover:text-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--accent))]",
}, },
@ -563,7 +550,7 @@ const SidebarMenuButton = React.forwardRef<
ref, ref,
) => { ) => {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : "button";
const { isMobile, state } = useSidebar(); const { state } = useSidebar();
const button = ( const button = (
<Comp <Comp
@ -592,7 +579,7 @@ const SidebarMenuButton = React.forwardRef<
<TooltipContent <TooltipContent
side="right" side="right"
align="center" align="center"
hidden={state !== "collapsed" || isMobile} hidden={state !== "collapsed"}
{...tooltip} {...tooltip}
/> />
</Tooltip> </Tooltip>
@ -615,9 +602,9 @@ const SidebarMenuAction = React.forwardRef<
ref={ref} ref={ref}
data-sidebar="menu-action" data-sidebar="menu-action"
className={cn( className={cn(
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-foreground outline-none ring-ring transition-transform hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0", "absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-foreground outline-none ring-ring transition-transform hover:bg-accent hover:text-accent-foreground focus-visible:ring-1 peer-hover/menu-button:text-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile. // Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden", "after:-inset-2 after:hidden",
"peer-data-[size=sm]/menu-button:top-1", "peer-data-[size=sm]/menu-button:top-1",
"peer-data-[size=default]/menu-button:top-1.5", "peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5", "peer-data-[size=lg]/menu-button:top-2.5",
@ -731,7 +718,7 @@ const SidebarMenuSubButton = React.forwardRef<
data-size={size} data-size={size}
data-active={isActive} data-active={isActive}
className={cn( className={cn(
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-foreground outline-none ring-ring hover:bg-accent hover:text-accent-foreground focus-visible:ring-2 active:bg-accent active:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-accent-foreground", "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-foreground outline-none ring-ring hover:bg-accent hover:text-accent-foreground focus-visible:ring-1 active:bg-accent active:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-accent-foreground",
"data-[active=true]:bg-accent data-[active=true]:text-accent-foreground", "data-[active=true]:bg-accent data-[active=true]:text-accent-foreground",
size === "sm" && "text-xs", size === "sm" && "text-xs",
size === "md" && "text-sm", size === "md" && "text-sm",

View file

@ -14,9 +14,7 @@ const SvgAWS = (props) => (
<style>{".st1{fill-rule:evenodd;clip-rule:evenodd;fill:#f90}"}</style> <style>{".st1{fill-rule:evenodd;clip-rule:evenodd;fill:#f90}"}</style>
<path <path
d="M86.4 66.4c0 3.7.4 6.7 1.1 8.9.8 2.2 1.8 4.6 3.2 7.2.5.8.7 1.6.7 2.3 0 1-.6 2-1.9 3L83.2 92c-.9.6-1.8.9-2.6.9-1 0-2-.5-3-1.4-1.4-1.5-2.6-3.1-3.6-4.7-1-1.7-2-3.6-3.1-5.9-7.8 9.2-17.6 13.8-29.4 13.8-8.4 0-15.1-2.4-20-7.2-4.9-4.8-7.4-11.2-7.4-19.2 0-8.5 3-15.4 9.1-20.6 6.1-5.2 14.2-7.8 24.5-7.8 3.4 0 6.9.3 10.6.8 3.7.5 7.5 1.3 11.5 2.2v-7.3c0-7.6-1.6-12.9-4.7-16-3.2-3.1-8.6-4.6-16.3-4.6-3.5 0-7.1.4-10.8 1.3-3.7.9-7.3 2-10.8 3.4-1.6.7-2.8 1.1-3.5 1.3-.7.2-1.2.3-1.6.3-1.4 0-2.1-1-2.1-3.1v-4.9c0-1.6.2-2.8.7-3.5.5-.7 1.4-1.4 2.8-2.1 3.5-1.8 7.7-3.3 12.6-4.5C41 1.9 46.2 1.3 51.7 1.3c11.9 0 20.6 2.7 26.2 8.1 5.5 5.4 8.3 13.6 8.3 24.6v32.4zM45.8 81.6c3.3 0 6.7-.6 10.3-1.8 3.6-1.2 6.8-3.4 9.5-6.4 1.6-1.9 2.8-4 3.4-6.4.6-2.4 1-5.3 1-8.7v-4.2c-2.9-.7-6-1.3-9.2-1.7-3.2-.4-6.3-.6-9.4-.6-6.7 0-11.6 1.3-14.9 4-3.3 2.7-4.9 6.5-4.9 11.5 0 4.7 1.2 8.2 3.7 10.6 2.4 2.5 5.9 3.7 10.5 3.7zm80.3 10.8c-1.8 0-3-.3-3.8-1-.8-.6-1.5-2-2.1-3.9L96.7 10.2c-.6-2-.9-3.3-.9-4 0-1.6.8-2.5 2.4-2.5h9.8c1.9 0 3.2.3 3.9 1 .8.6 1.4 2 2 3.9l16.8 66.2 15.6-66.2c.5-2 1.1-3.3 1.9-3.9.8-.6 2.2-1 4-1h8c1.9 0 3.2.3 4 1 .8.6 1.5 2 1.9 3.9l15.8 67 17.3-67c.6-2 1.3-3.3 2-3.9.8-.6 2.1-1 3.9-1h9.3c1.6 0 2.5.8 2.5 2.5 0 .5-.1 1-.2 1.6-.1.6-.3 1.4-.7 2.5l-24.1 77.3c-.6 2-1.3 3.3-2.1 3.9-.8.6-2.1 1-3.8 1h-8.6c-1.9 0-3.2-.3-4-1-.8-.7-1.5-2-1.9-4L156 23l-15.4 64.4c-.5 2-1.1 3.3-1.9 4-.8.7-2.2 1-4 1h-8.6zm128.5 2.7c-5.2 0-10.4-.6-15.4-1.8-5-1.2-8.9-2.5-11.5-4-1.6-.9-2.7-1.9-3.1-2.8-.4-.9-.6-1.9-.6-2.8v-5.1c0-2.1.8-3.1 2.3-3.1.6 0 1.2.1 1.8.3.6.2 1.5.6 2.5 1 3.4 1.5 7.1 2.7 11 3.5 4 .8 7.9 1.2 11.9 1.2 6.3 0 11.2-1.1 14.6-3.3 3.4-2.2 5.2-5.4 5.2-9.5 0-2.8-.9-5.1-2.7-7-1.8-1.9-5.2-3.6-10.1-5.2L246 52c-7.3-2.3-12.7-5.7-16-10.2-3.3-4.4-5-9.3-5-14.5 0-4.2.9-7.9 2.7-11.1 1.8-3.2 4.2-6 7.2-8.2 3-2.3 6.4-4 10.4-5.2 4-1.2 8.2-1.7 12.6-1.7 2.2 0 4.5.1 6.7.4 2.3.3 4.4.7 6.5 1.1 2 .5 3.9 1 5.7 1.6 1.8.6 3.2 1.2 4.2 1.8 1.4.8 2.4 1.6 3 2.5.6.8.9 1.9.9 3.3v4.7c0 2.1-.8 3.2-2.3 3.2-.8 0-2.1-.4-3.8-1.2-5.7-2.6-12.1-3.9-19.2-3.9-5.7 0-10.2.9-13.3 2.8-3.1 1.9-4.7 4.8-4.7 8.9 0 2.8 1 5.2 3 7.1 2 1.9 5.7 3.8 11 5.5l14.2 4.5c7.2 2.3 12.4 5.5 15.5 9.6 3.1 4.1 4.6 8.8 4.6 14 0 4.3-.9 8.2-2.6 11.6-1.8 3.4-4.2 6.4-7.3 8.8-3.1 2.5-6.8 4.3-11.1 5.6-4.5 1.4-9.2 2.1-14.3 2.1z" d="M86.4 66.4c0 3.7.4 6.7 1.1 8.9.8 2.2 1.8 4.6 3.2 7.2.5.8.7 1.6.7 2.3 0 1-.6 2-1.9 3L83.2 92c-.9.6-1.8.9-2.6.9-1 0-2-.5-3-1.4-1.4-1.5-2.6-3.1-3.6-4.7-1-1.7-2-3.6-3.1-5.9-7.8 9.2-17.6 13.8-29.4 13.8-8.4 0-15.1-2.4-20-7.2-4.9-4.8-7.4-11.2-7.4-19.2 0-8.5 3-15.4 9.1-20.6 6.1-5.2 14.2-7.8 24.5-7.8 3.4 0 6.9.3 10.6.8 3.7.5 7.5 1.3 11.5 2.2v-7.3c0-7.6-1.6-12.9-4.7-16-3.2-3.1-8.6-4.6-16.3-4.6-3.5 0-7.1.4-10.8 1.3-3.7.9-7.3 2-10.8 3.4-1.6.7-2.8 1.1-3.5 1.3-.7.2-1.2.3-1.6.3-1.4 0-2.1-1-2.1-3.1v-4.9c0-1.6.2-2.8.7-3.5.5-.7 1.4-1.4 2.8-2.1 3.5-1.8 7.7-3.3 12.6-4.5C41 1.9 46.2 1.3 51.7 1.3c11.9 0 20.6 2.7 26.2 8.1 5.5 5.4 8.3 13.6 8.3 24.6v32.4zM45.8 81.6c3.3 0 6.7-.6 10.3-1.8 3.6-1.2 6.8-3.4 9.5-6.4 1.6-1.9 2.8-4 3.4-6.4.6-2.4 1-5.3 1-8.7v-4.2c-2.9-.7-6-1.3-9.2-1.7-3.2-.4-6.3-.6-9.4-.6-6.7 0-11.6 1.3-14.9 4-3.3 2.7-4.9 6.5-4.9 11.5 0 4.7 1.2 8.2 3.7 10.6 2.4 2.5 5.9 3.7 10.5 3.7zm80.3 10.8c-1.8 0-3-.3-3.8-1-.8-.6-1.5-2-2.1-3.9L96.7 10.2c-.6-2-.9-3.3-.9-4 0-1.6.8-2.5 2.4-2.5h9.8c1.9 0 3.2.3 3.9 1 .8.6 1.4 2 2 3.9l16.8 66.2 15.6-66.2c.5-2 1.1-3.3 1.9-3.9.8-.6 2.2-1 4-1h8c1.9 0 3.2.3 4 1 .8.6 1.5 2 1.9 3.9l15.8 67 17.3-67c.6-2 1.3-3.3 2-3.9.8-.6 2.1-1 3.9-1h9.3c1.6 0 2.5.8 2.5 2.5 0 .5-.1 1-.2 1.6-.1.6-.3 1.4-.7 2.5l-24.1 77.3c-.6 2-1.3 3.3-2.1 3.9-.8.6-2.1 1-3.8 1h-8.6c-1.9 0-3.2-.3-4-1-.8-.7-1.5-2-1.9-4L156 23l-15.4 64.4c-.5 2-1.1 3.3-1.9 4-.8.7-2.2 1-4 1h-8.6zm128.5 2.7c-5.2 0-10.4-.6-15.4-1.8-5-1.2-8.9-2.5-11.5-4-1.6-.9-2.7-1.9-3.1-2.8-.4-.9-.6-1.9-.6-2.8v-5.1c0-2.1.8-3.1 2.3-3.1.6 0 1.2.1 1.8.3.6.2 1.5.6 2.5 1 3.4 1.5 7.1 2.7 11 3.5 4 .8 7.9 1.2 11.9 1.2 6.3 0 11.2-1.1 14.6-3.3 3.4-2.2 5.2-5.4 5.2-9.5 0-2.8-.9-5.1-2.7-7-1.8-1.9-5.2-3.6-10.1-5.2L246 52c-7.3-2.3-12.7-5.7-16-10.2-3.3-4.4-5-9.3-5-14.5 0-4.2.9-7.9 2.7-11.1 1.8-3.2 4.2-6 7.2-8.2 3-2.3 6.4-4 10.4-5.2 4-1.2 8.2-1.7 12.6-1.7 2.2 0 4.5.1 6.7.4 2.3.3 4.4.7 6.5 1.1 2 .5 3.9 1 5.7 1.6 1.8.6 3.2 1.2 4.2 1.8 1.4.8 2.4 1.6 3 2.5.6.8.9 1.9.9 3.3v4.7c0 2.1-.8 3.2-2.3 3.2-.8 0-2.1-.4-3.8-1.2-5.7-2.6-12.1-3.9-19.2-3.9-5.7 0-10.2.9-13.3 2.8-3.1 1.9-4.7 4.8-4.7 8.9 0 2.8 1 5.2 3 7.1 2 1.9 5.7 3.8 11 5.5l14.2 4.5c7.2 2.3 12.4 5.5 15.5 9.6 3.1 4.1 4.6 8.8 4.6 14 0 4.3-.9 8.2-2.6 11.6-1.8 3.4-4.2 6.4-7.3 8.8-3.1 2.5-6.8 4.3-11.1 5.6-4.5 1.4-9.2 2.1-14.3 2.1z"
style={{ fill={props.isdark ? "#ffffff" : "#252f3e"}
fill: "#252f3e",
}}
/> />
<path <path
d="M273.5 143.7c-32.9 24.3-80.7 37.2-121.8 37.2-57.6 0-109.5-21.3-148.7-56.7-3.1-2.8-.3-6.6 3.4-4.4 42.4 24.6 94.7 39.5 148.8 39.5 36.5 0 76.6-7.6 113.5-23.2 5.5-2.5 10.2 3.6 4.8 7.6z" d="M273.5 143.7c-32.9 24.3-80.7 37.2-121.8 37.2-57.6 0-109.5-21.3-148.7-56.7-3.1-2.8-.3-6.6 3.4-4.4 42.4 24.6 94.7 39.5 148.8 39.5 36.5 0 76.6-7.6 113.5-23.2 5.5-2.5 10.2 3.6 4.8 7.6z"

View file

@ -1,8 +1,10 @@
import { useDarkStore } from "@/stores/darkStore";
import React, { forwardRef } from "react"; import React, { forwardRef } from "react";
import SvgAWS from "./AWS"; import SvgAWS from "./AWS";
export const AWSIcon = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>( export const AWSIcon = forwardRef<SVGSVGElement, React.PropsWithChildren<{}>>(
(props, ref) => { (props, ref) => {
return <SvgAWS ref={ref} {...props} />; const isdark = useDarkStore((state) => state.dark);
return <SvgAWS ref={ref} isdark={isdark} {...props} />;
}, },
); );

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before After
Before After

View file

@ -27,17 +27,9 @@ export const GradientSave = forwardRef<
>((props, ref) => { >((props, ref) => {
return ( return (
<> <>
<svg width="0" height="0" style={{ position: "absolute" }}>
<defs>
<linearGradient id="grad2" x1="0%" y1="0%" x2="100%" y2="0%">
<stop className="gradient-start" offset="0%" />
<stop className="gradient-end" offset="100%" />
</linearGradient>
</defs>
</svg>
<ForwardedIconComponent <ForwardedIconComponent
name="Save" name="Save"
stroke="url(#grad2)" stroke="url(#x-gradient)"
ref={ref} ref={ref}
{...props} {...props}
/> />

View file

@ -6,6 +6,7 @@ export const SvgRedis = (props) => (
height="35" height="35"
version="1" version="1"
viewBox="0 0 750 750" viewBox="0 0 750 750"
{...props}
> >
<defs> <defs>
<filter id="959fca5e72" width="100%" height="100%" x="0%" y="0%"> <filter id="959fca5e72" width="100%" height="100%" x="0%" y="0%">

View file

@ -4,7 +4,9 @@ import CanvasControls, {
CustomControlButton, CustomControlButton,
} from "@/components/canvasControlsComponent"; } from "@/components/canvasControlsComponent";
import FlowToolbar from "@/components/flowToolbarComponent"; import FlowToolbar from "@/components/flowToolbarComponent";
import ForwardedIconComponent from "@/components/genericIconComponent";
import LoadingComponent from "@/components/loadingComponent"; import LoadingComponent from "@/components/loadingComponent";
import { SidebarTrigger, useSidebar } from "@/components/ui/sidebar";
import { import {
NOTE_NODE_MIN_HEIGHT, NOTE_NODE_MIN_HEIGHT,
NOTE_NODE_MIN_WIDTH, NOTE_NODE_MIN_WIDTH,
@ -16,7 +18,7 @@ import useAutoSaveFlow from "@/hooks/flows/use-autosave-flow";
import useUploadFlow from "@/hooks/flows/use-upload-flow"; import useUploadFlow from "@/hooks/flows/use-upload-flow";
import { useAddComponent } from "@/hooks/useAddComponent"; import { useAddComponent } from "@/hooks/useAddComponent";
import { nodeColorsName } from "@/utils/styleUtils"; import { nodeColorsName } from "@/utils/styleUtils";
import { isSupportedNodeTypes } from "@/utils/utils"; import { cn, isSupportedNodeTypes } from "@/utils/utils";
import _, { cloneDeep } from "lodash"; import _, { cloneDeep } from "lodash";
import { import {
KeyboardEvent, KeyboardEvent,
@ -33,6 +35,7 @@ import ReactFlow, {
Edge, Edge,
NodeDragHandler, NodeDragHandler,
OnSelectionChangeParams, OnSelectionChangeParams,
Panel,
SelectionDragHandler, SelectionDragHandler,
updateEdge, updateEdge,
useReactFlow, useReactFlow,
@ -583,6 +586,8 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
document.documentElement.style.setProperty("--selected", innerColor); document.documentElement.style.setProperty("--selected", innerColor);
}; };
const { open } = useSidebar();
return ( return (
<div className="h-full w-full bg-canvas" ref={reactFlowWrapper}> <div className="h-full w-full bg-canvas" ref={reactFlowWrapper}>
{showCanvas ? ( {showCanvas ? (
@ -640,6 +645,23 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
<FlowToolbar /> <FlowToolbar />
</> </>
)} )}
<Panel
className={cn(
"react-flow__controls !m-2 flex gap-1.5 rounded-md border border-secondary-hover bg-background fill-foreground stroke-foreground p-1.5 text-primary shadow transition-all duration-300 [&>button]:border-0 [&>button]:bg-background hover:[&>button]:bg-accent",
open
? "pointer-events-none -translate-x-full opacity-0"
: "pointer-events-auto opacity-100",
)}
position="top-left"
>
<SidebarTrigger className="h-fit w-fit px-3 py-1.5">
<ForwardedIconComponent
name="PanelRightClose"
className="h-4 w-4"
/>
Components
</SidebarTrigger>
</Panel>
<SelectionMenu <SelectionMenu
lastSelection={lastSelection} lastSelection={lastSelection}
isVisible={selectionMenuVisible} isVisible={selectionMenuVisible}

View file

@ -12,11 +12,11 @@ export function SidebarFilterComponent({
resetFilters: () => void; resetFilters: () => void;
}) { }) {
return ( return (
<div className="mb-0.5 flex w-full items-center justify-between rounded border bg-accent-indigo p-2 text-sm text-accent-indigo-foreground"> <div className="mb-0.5 flex w-full items-center justify-between rounded border bg-accent-indigo p-2 text-sm text-foreground">
<div className="flex flex-1 items-center gap-1.5"> <div className="flex flex-1 items-center gap-1.5">
<ForwardedIconComponent <ForwardedIconComponent
name="ListFilter" name="ListFilter"
className="h-4 w-4 shrink-0 stroke-2" className="h-4 w-4 shrink-0 stroke-2 text-accent-indigo-foreground"
/> />
<div className="flex flex-1"> <div className="flex flex-1">
{isInput ? "Input" : "Output"}:{" "} {isInput ? "Input" : "Output"}:{" "}

View file

@ -6,6 +6,7 @@ import { DragEventHandler, forwardRef, useRef, useState } from "react";
import IconComponent, { import IconComponent, {
ForwardedIconComponent, ForwardedIconComponent,
} from "../../../../../../components/genericIconComponent"; } from "../../../../../../components/genericIconComponent";
import ShadTooltip from "../../../../../../components/shadTooltipComponent";
import { import {
Select, Select,
SelectContent, SelectContent,
@ -118,7 +119,7 @@ export const SidebarDraggableComponent = forwardRef(
data-testid={sectionName + display_name} data-testid={sectionName + display_name}
id={sectionName + display_name} id={sectionName + display_name}
className={cn( className={cn(
"group/draggable flex cursor-grab items-center gap-2 rounded-md bg-muted p-3 hover:bg-accent", "group/draggable flex cursor-grab items-center gap-2 rounded-md bg-muted p-3 hover:bg-secondary-hover/75",
error ? "cursor-not-allowed select-none" : "", error ? "cursor-not-allowed select-none" : "",
)} )}
draggable={!error} draggable={!error}
@ -134,9 +135,11 @@ export const SidebarDraggableComponent = forwardRef(
> >
<ForwardedIconComponent name={icon} className="h-5 w-5 shrink-0" /> <ForwardedIconComponent name={icon} className="h-5 w-5 shrink-0" />
<div className="flex flex-1 items-center overflow-hidden"> <div className="flex flex-1 items-center overflow-hidden">
<span className="truncate text-sm font-semibold"> <ShadTooltip content={display_name} styleClasses="z-50">
{display_name} <span className="truncate text-sm font-semibold">
</span> {display_name}
</span>
</ShadTooltip>
{beta && ( {beta && (
<Badge <Badge
variant="pinkStatic" variant="pinkStatic"
@ -161,18 +164,18 @@ export const SidebarDraggableComponent = forwardRef(
variant="ghost" variant="ghost"
size="icon" size="icon"
tabIndex={-1} tabIndex={-1}
className="text-muted-foreground hover:text-primary group-focus/draggable:text-primary" className="text-primary"
onClick={() => addComponent(apiClass, itemName)} onClick={() => addComponent(apiClass, itemName)}
> >
<ForwardedIconComponent <ForwardedIconComponent
name="Plus" name="Plus"
className="h-4 w-4 shrink-0 opacity-0 transition-all group-hover/draggable:opacity-100 group-focus/draggable:opacity-100" className="h-4 w-4 shrink-0 transition-all group-hover/draggable:opacity-100 group-focus/draggable:opacity-100 sm:opacity-0"
/> />
</Button> </Button>
<div ref={popoverRef}> <div ref={popoverRef}>
<ForwardedIconComponent <ForwardedIconComponent
name="GripVertical" name="GripVertical"
className="h-4 w-4 shrink-0 text-muted-foreground" className="h-4 w-4 shrink-0 text-muted-foreground group-hover/draggable:text-primary"
/> />
<SelectTrigger tabIndex={-1}></SelectTrigger> <SelectTrigger tabIndex={-1}></SelectTrigger>
<SelectContent <SelectContent

View file

@ -6,11 +6,6 @@ import ForwardedIconComponent from "@/components/genericIconComponent";
import ShadTooltip from "@/components/shadTooltipComponent"; import ShadTooltip from "@/components/shadTooltipComponent";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { import {
Disclosure, Disclosure,
DisclosureContent, DisclosureContent,
@ -29,6 +24,7 @@ import {
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
SidebarMenuSkeleton, SidebarMenuSkeleton,
SidebarTrigger,
} from "@/components/ui/sidebar"; } from "@/components/ui/sidebar";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { CustomLink } from "@/customization/components/custom-link"; import { CustomLink } from "@/customization/components/custom-link";
@ -302,23 +298,41 @@ export function FlowSidebarComponent() {
} }
}; };
const hasBundleItems = bundles.some(
(item) =>
dataFilter[item.name] && Object.keys(dataFilter[item.name]).length > 0,
);
function handleClearSearch() {
setSearch("");
setFilterData(data);
setOpenCategories([]);
}
return ( return (
<Sidebar data-testid="shad-sidebar"> <Sidebar collapsible="offcanvas" data-testid="shad-sidebar">
<SidebarHeader className="flex w-full flex-col gap-4 p-4 pb-1"> <SidebarHeader className="flex w-full flex-col gap-4 p-4 pb-1">
<Disclosure open={showConfig} onOpenChange={setShowConfig}> <Disclosure open={showConfig} onOpenChange={setShowConfig}>
<div className="flex w-full items-center justify-between"> <div className="flex w-full items-center gap-2">
<h3 className="text-sm font-semibold">Components</h3> <SidebarTrigger className="text-muted-foreground">
<ForwardedIconComponent name="PanelLeftClose" />
</SidebarTrigger>
<h3 className="flex-1 text-sm font-semibold">Components</h3>
<DisclosureTrigger> <DisclosureTrigger>
<Button <div>
variant={showConfig ? "ghostActive" : "ghost"} <ShadTooltip content="Component settings" styleClasses="z-50">
size="iconMd" <Button
data-testid="sidebar-options-trigger" variant={showConfig ? "ghostActive" : "ghost"}
> size="iconMd"
<ForwardedIconComponent data-testid="sidebar-options-trigger"
name="SlidersHorizontal" >
className="h-4 w-4" <ForwardedIconComponent
/> name="SlidersHorizontal"
</Button> className="h-4 w-4"
/>
</Button>
</ShadTooltip>
</div>
</DisclosureTrigger> </DisclosureTrigger>
</div> </div>
<DisclosureContent> <DisclosureContent>
@ -368,6 +382,7 @@ export function FlowSidebarComponent() {
type="search" type="search"
data-testid="sidebar-search-input" data-testid="sidebar-search-input"
className="w-full rounded-lg bg-background pl-8 text-sm" className="w-full rounded-lg bg-background pl-8 text-sm"
placeholder=""
onFocus={() => setIsInputFocused(true)} onFocus={() => setIsInputFocused(true)}
onBlur={() => setIsInputFocused(false)} onBlur={() => setIsInputFocused(false)}
value={search} value={search}
@ -410,9 +425,8 @@ export function FlowSidebarComponent() {
(item) => (item) =>
dataFilter[item.name] && dataFilter[item.name] &&
Object.keys(dataFilter[item.name]).length > 0 && ( Object.keys(dataFilter[item.name]).length > 0 && (
<Collapsible <Disclosure
key={item.name} key={item.name}
className="group/collapsible"
open={openCategories.includes(item.name)} open={openCategories.includes(item.name)}
onOpenChange={(isOpen) => { onOpenChange={(isOpen) => {
setOpenCategories((prev) => setOpenCategories((prev) =>
@ -423,7 +437,7 @@ export function FlowSidebarComponent() {
}} }}
> >
<SidebarMenuItem> <SidebarMenuItem>
<CollapsibleTrigger asChild> <DisclosureTrigger className="group/collapsible">
<SidebarMenuButton asChild> <SidebarMenuButton asChild>
<div <div
data-testid={`disclosure-${item.display_name.toLocaleLowerCase()}`} data-testid={`disclosure-${item.display_name.toLocaleLowerCase()}`}
@ -435,19 +449,19 @@ export function FlowSidebarComponent() {
> >
<ForwardedIconComponent <ForwardedIconComponent
name={item.icon} name={item.icon}
className="h-4 w-4 text-muted-foreground group-data-[state=open]/collapsible:text-pink-600 group-data-[state=open]/collapsible:dark:text-pink-400" className="group-aria-expanded/collapsible:x-gradient h-4 w-4"
/> />
<span className="group-data-[state=open]/collapsible:font-semibold"> <span className="group-aria-expanded/collapsible:font-semibold">
{item.display_name} {item.display_name}
</span> </span>
<ForwardedIconComponent <ForwardedIconComponent
name="ChevronRight" name="ChevronRight"
className="h-4 w-4 text-muted-foreground transition-all group-data-[state=open]/collapsible:rotate-90" className="h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
/> />
</div> </div>
</SidebarMenuButton> </SidebarMenuButton>
</CollapsibleTrigger> </DisclosureTrigger>
<CollapsibleContent> <DisclosureContent>
<div className="flex flex-col gap-1 py-2"> <div className="flex flex-col gap-1 py-2">
{Object.keys(dataFilter[item.name]) {Object.keys(dataFilter[item.name])
.sort((a, b) => .sort((a, b) =>
@ -516,152 +530,147 @@ export function FlowSidebarComponent() {
</ShadTooltip> </ShadTooltip>
))} ))}
</div> </div>
</CollapsibleContent> </DisclosureContent>
</SidebarMenuItem> </SidebarMenuItem>
</Collapsible> </Disclosure>
), ),
)} )}
</SidebarMenu> </SidebarMenu>
</SidebarGroupContent> </SidebarGroupContent>
</SidebarGroup> </SidebarGroup>
<SidebarGroup> {hasBundleItems && (
<SidebarGroupLabel>Bundles</SidebarGroupLabel> <SidebarGroup>
<SidebarGroupContent> <SidebarGroupLabel>Bundles</SidebarGroupLabel>
<SidebarMenu> <SidebarGroupContent>
{!data <SidebarMenu>
? Array.from({ length: 5 }).map((_, index) => ( {bundles.map(
<SidebarMenuItem key={index}> (item) =>
<SidebarMenuSkeleton /> dataFilter[item.name] &&
</SidebarMenuItem> Object.keys(dataFilter[item.name]).length > 0 && (
)) <Disclosure
: bundles.map( key={item.name}
(item) => open={openCategories.includes(item.name)}
dataFilter[item.name] && onOpenChange={(isOpen) => {
Object.keys(dataFilter[item.name]).length > 0 && ( setOpenCategories((prev) =>
<Collapsible isOpen
key={item.name} ? [...prev, item.name]
className="group/collapsible" : prev.filter((cat) => cat !== item.name),
open={openCategories.includes(item.name)} );
onOpenChange={(isOpen) => { }}
setOpenCategories((prev) => >
isOpen <SidebarMenuItem>
? [...prev, item.name] <DisclosureTrigger className="group/collapsible">
: prev.filter((cat) => cat !== item.name), <SidebarMenuButton asChild>
); <div
}} tabIndex={0}
> onKeyDown={(e) =>
<SidebarMenuItem> handleKeyDown(e, item.name)
<CollapsibleTrigger asChild> }
<SidebarMenuButton asChild> className="flex cursor-pointer items-center gap-2"
<div >
tabIndex={0} <ForwardedIconComponent
onKeyDown={(e) => name={item.icon}
handleKeyDown(e, item.name) className="h-4 w-4 text-muted-foreground group-aria-expanded/collapsible:text-primary"
} />
className="flex cursor-pointer items-center gap-2" <span className="group-aria-expanded/collapsible:font-semibold">
> {item.display_name}
<ForwardedIconComponent </span>
name={item.icon} <ForwardedIconComponent
className="h-4 w-4 text-muted-foreground group-data-[state=open]/collapsible:text-pink-600 group-data-[state=open]/collapsible:dark:text-pink-400" name="ChevronRight"
/> className="h-4 w-4 text-muted-foreground transition-all group-aria-expanded/collapsible:rotate-90"
<span className="group-data-[state=open]/collapsible:font-semibold"> />
{item.display_name} </div>
</span> </SidebarMenuButton>
<ForwardedIconComponent </DisclosureTrigger>
name="ChevronRight" <DisclosureContent>
className="h-4 w-4 text-muted-foreground transition-all group-data-[state=open]/collapsible:rotate-90" <div className="flex flex-col gap-1 py-2">
/> {Object.keys(dataFilter[item.name])
</div> .sort((a, b) =>
</SidebarMenuButton> sensitiveSort(
</CollapsibleTrigger> dataFilter[item.name][a].display_name,
<CollapsibleContent> dataFilter[item.name][b].display_name,
<div className="flex flex-col gap-1 py-2"> ),
{Object.keys(dataFilter[item.name]) )
.sort((a, b) => .map((SBItemName: string, idx) => (
sensitiveSort( <ShadTooltip
dataFilter[item.name][a].display_name, content={
dataFilter[item.name][b].display_name, dataFilter[item.name][SBItemName]
), .display_name
) }
.map((SBItemName: string, idx) => ( side="right"
<ShadTooltip key={idx}
content={ >
<SidebarDraggableComponent
sectionName={item.name as string}
apiClass={
dataFilter[item.name][SBItemName]
}
icon={
dataFilter[item.name][SBItemName]
.icon ??
item.icon ??
"Unknown"
}
key={idx}
onDragStart={(event) =>
onDragStart(event, {
type: removeCountFromString(
SBItemName,
),
node: dataFilter[item.name][
SBItemName
],
})
}
color={nodeColors[item.name]}
itemName={SBItemName}
error={
!!dataFilter[item.name][SBItemName]
.error
}
display_name={
dataFilter[item.name][SBItemName] dataFilter[item.name][SBItemName]
.display_name .display_name
} }
side="right" official={
key={idx} dataFilter[item.name][SBItemName]
> .official === false
<SidebarDraggableComponent ? false
sectionName={item.name as string} : true
apiClass={ }
dataFilter[item.name][SBItemName] beta={
} dataFilter[item.name][SBItemName]
icon={ .beta ?? false
dataFilter[item.name][SBItemName] }
.icon ?? legacy={
item.icon ?? dataFilter[item.name][SBItemName]
"Unknown" .legacy ?? false
} }
key={idx} />
onDragStart={(event) => </ShadTooltip>
onDragStart(event, { ))}
type: removeCountFromString( </div>
SBItemName, </DisclosureContent>
), </SidebarMenuItem>
node: dataFilter[item.name][ </Disclosure>
SBItemName ),
], )}
}) </SidebarMenu>
} </SidebarGroupContent>
color={nodeColors[item.name]} </SidebarGroup>
itemName={SBItemName} )}
error={
!!dataFilter[item.name][
SBItemName
].error
}
display_name={
dataFilter[item.name][SBItemName]
.display_name
}
official={
dataFilter[item.name][SBItemName]
.official === false
? false
: true
}
beta={
dataFilter[item.name][SBItemName]
.beta ?? false
}
legacy={
dataFilter[item.name][SBItemName]
.legacy ?? false
}
/>
</ShadTooltip>
))}
</div>
</CollapsibleContent>
</SidebarMenuItem>
</Collapsible>
),
)}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</> </>
) : ( ) : (
<div className="flex h-full flex-col items-center justify-center p-4 text-center"> <div className="flex h-full flex-col items-center justify-center text-center">
<ForwardedIconComponent <p className="text-sm text-secondary-foreground">
name="Search" No components found.{" "}
className="mb-4 h-8 w-8 text-muted-foreground" <a
/> className="cursor-pointer underline underline-offset-4"
<h3 className="mb-2 text-lg font-semibold">No results found</h3> onClick={handleClearSearch}
<p className="text-sm text-muted-foreground"> >
Try adjusting your search or filter to find what you're looking Clear your search
for. </a>{" "}
or filter and try a different query.
</p> </p>
</div> </div>
)} )}
@ -669,15 +678,24 @@ export function FlowSidebarComponent() {
<SidebarFooter className="border-t p-4 py-3"> <SidebarFooter className="border-t p-4 py-3">
{hasStore && ( {hasStore && (
<SidebarMenuButton asChild> <SidebarMenuButton asChild>
<CustomLink to="/store"> <CustomLink
<div className="flex items-center gap-2"> to="/store"
target="_blank"
rel="noopener noreferrer"
className="group/discover"
>
<div className="flex w-full items-center gap-2">
<ForwardedIconComponent <ForwardedIconComponent
name="Store" name="Store"
className="h-4 w-4 text-muted-foreground" className="h-4 w-4 text-muted-foreground"
/> />
<span className="group-data-[state=open]/collapsible:font-semibold"> <span className="flex-1 group-data-[state=open]/collapsible:font-semibold">
Discover more components Discover more components
</span> </span>
<ForwardedIconComponent
name="SquareArrowOutUpRight"
className="h-4 w-4 opacity-0 transition-all group-hover/discover:opacity-100"
/>
</div> </div>
</CustomLink> </CustomLink>
</SidebarMenuButton> </SidebarMenuButton>

View file

@ -18,7 +18,7 @@ export default function ShortcutDisplay({
{name && <span> {name} </span>} {name && <span> {name} </span>}
<span <span
className={cn( className={cn(
"flex items-center rounded-sm bg-muted px-1.5 py-[0.1em] text-lg text-muted-foreground", "flex h-5 items-center rounded-sm bg-muted px-1.5 text-lg text-muted-foreground",
name && "ml-3", name && "ml-3",
)} )}
> >

View file

@ -3,13 +3,13 @@ import { useGetFlow } from "@/controllers/API/queries/flows/use-get-flow";
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows"; import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate"; import { useCustomNavigate } from "@/customization/hooks/use-custom-navigate";
import useSaveFlow from "@/hooks/flows/use-save-flow"; import useSaveFlow from "@/hooks/flows/use-save-flow";
import { useIsMobile } from "@/hooks/use-mobile";
import { SaveChangesModal } from "@/modals/saveChangesModal"; import { SaveChangesModal } from "@/modals/saveChangesModal";
import useAlertStore from "@/stores/alertStore"; import useAlertStore from "@/stores/alertStore";
import { useTypesStore } from "@/stores/typesStore"; import { useTypesStore } from "@/stores/typesStore";
import { customStringify } from "@/utils/reactflowUtils"; import { customStringify } from "@/utils/reactflowUtils";
import { useEffect } from "react"; import { useEffect } from "react";
import { useBlocker, useParams } from "react-router-dom"; import { useBlocker, useParams } from "react-router-dom";
import FlowToolbar from "../../components/flowToolbarComponent";
import { useDarkStore } from "../../stores/darkStore"; import { useDarkStore } from "../../stores/darkStore";
import useFlowStore from "../../stores/flowStore"; import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore";
@ -160,12 +160,14 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
setCurrentFlow(flow); setCurrentFlow(flow);
}; };
const isMobile = useIsMobile();
return ( return (
<> <>
<div className="flow-page-positioning"> <div className="flow-page-positioning">
{currentFlow && ( {currentFlow && (
<div className="flex h-full overflow-hidden"> <div className="flex h-full overflow-hidden">
<SidebarProvider> <SidebarProvider width="19rem" defaultOpen={!isMobile}>
{!view && <FlowSidebarComponent />} {!view && <FlowSidebarComponent />}
<main className="flex flex-1"> <main className="flex flex-1">
<div className="h-full w-full"> <div className="h-full w-full">

View file

@ -1267,10 +1267,6 @@
@apply flex w-max min-w-10 items-center gap-1 rounded-lg text-foreground; @apply flex w-max min-w-10 items-center gap-1 rounded-lg text-foreground;
} }
.share-button {
@apply relative inline-flex h-full w-full items-center justify-center gap-1.5 rounded px-3 py-1.5 text-sm font-semibold text-foreground transition-all duration-150 ease-in-out hover:bg-accent;
}
.last-output-border { .last-output-border {
@apply rounded-b-[12px]; @apply rounded-b-[12px];
} }

View file

@ -272,9 +272,10 @@ pre {
background-color: hsl(var(--code-background)) !important; background-color: hsl(var(--code-background)) !important;
} }
[type="search"]::-webkit-search-cancel-button { [type="search"]:not(:placeholder-shown)::-webkit-search-cancel-button {
-webkit-appearance: none; -webkit-appearance: none;
background-color: hsl(var(--primary)); background-color: hsl(var(--primary));
opacity: 1 !important;
-webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23777'><path d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/></svg>"); -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23777'><path d='M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/></svg>");
background-size: 20px 20px; background-size: 20px 20px;
height: 20px; height: 20px;

View file

@ -91,8 +91,8 @@
--note-indigo: #e0e7ff; --note-indigo: #e0e7ff;
--note-emerald: #d1fae5; --note-emerald: #d1fae5;
--note-red: #fee2e2; --note-red: #fee2e2;
--error-red:0,86%,97%; /*hsla(0, 86%, 97%)*/ --error-red: 0, 86%, 97%; /*hsla(0, 86%, 97%)*/
--error-red-border: 0,96%,89%; /*hsla(0,96%,89%)*/ --error-red-border: 0, 96%, 89%; /*hsla(0,96%,89%)*/
--note-default-opacity: #f1f5f980; --note-default-opacity: #f1f5f980;
--note-indigo-opacity: #312e8180; --note-indigo-opacity: #312e8180;
--note-emerald-opacity: #064e3b80; --note-emerald-opacity: #064e3b80;
@ -159,17 +159,17 @@
--background: 240 6% 10%; /* hsl(240, 6%, 10%) */ --background: 240 6% 10%; /* hsl(240, 6%, 10%) */
--muted: 240 4% 16%; /* hsl(240, 4%, 16%) */ --muted: 240 4% 16%; /* hsl(240, 4%, 16%) */
--muted-foreground: 240 5% 65%; /* hsl(240, 5%, 65%) */ --muted-foreground: 240 5% 65%; /* hsl(240, 5%, 65%) */
--card: 0 0% 0%; /* hsl(0, 0, 0%) */ --card: 240 6% 10%; /* hsl(240, 6%, 10%) */
--card-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */ --card-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */
--popover: 0 0% 0%; /* hsl(0, 0%, 0%) */ --popover: 240 6% 10%; /* hsl(240, 6%, 10%) */
--popover-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */ --popover-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */
--border: 240 4% 16%; /* hsl(240, 4%, 16%) */ --border: 240 5% 26%; /* hsl(240, 5%, 26%) */
--input: 240 5% 26%; /* hsl(240, 5%, 26%) */ --input: 240 5% 34%; /* hsl(240, 5%, 34%) */
--primary-foreground: 0 0% 0%; /* hsl(0, 0%, 0%) */ --primary-foreground: 0 0% 0%; /* hsl(0, 0%, 0%) */
--primary: 0 0% 100%; /* hsl(0, 0%, 100%) */ --primary: 0 0% 100%; /* hsl(0, 0%, 100%) */
--secondary: 0 0% 0%; /* hsl(0, 0%, 0%) */ --secondary: 0 0% 0%; /* hsl(0, 0%, 0%) */
--secondary-foreground: 240 6% 90%; /* hsl(240, 6%, 90%) */ --secondary-foreground: 240 6% 90%; /* hsl(240, 6%, 90%) */
--accent: 240 6% 10%; /* hsl(240, 6%, 10%) */ --accent: 240 4% 16%; /* hsl(240, 4%, 16%) */
--accent-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */ --accent-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */
--destructive: 0 84% 60%; /* hsl(0, 84%, 60%) */ --destructive: 0 84% 60%; /* hsl(0, 84%, 60%) */
--destructive-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */ --destructive-foreground: 0 0% 100%; /* hsl(0, 0%, 100%) */
@ -177,7 +177,7 @@
--primary-hover: 240 6% 90%; /* hsl(240, 6%, 90%) */ --primary-hover: 240 6% 90%; /* hsl(240, 6%, 90%) */
--secondary-hover: 240 4% 16%; /* hsl(240, 4%, 16%) */ --secondary-hover: 240 4% 16%; /* hsl(240, 4%, 16%) */
--placeholder-foreground: 240 4% 46%; /* hsl(240, 4%, 46%) */ --placeholder-foreground: 240 4% 46%; /* hsl(240, 4%, 46%) */
--canvas: 240 6% 10%; /* hsl(240, 6%, 10%) */ --canvas: 0 0% 0%; /* hsl(0, 0%, 0%) */
--accent-emerald: 164 86% 16%; /* hsl(164, 86%, 16%) */ --accent-emerald: 164 86% 16%; /* hsl(164, 86%, 16%) */
--accent-emerald-foreground: 158 64% 52%; /* hsl(158, 64%, 52%) */ --accent-emerald-foreground: 158 64% 52%; /* hsl(158, 64%, 52%) */
--accent-indigo: 242 25% 34%; /* hsl(242, 25%, 34%) */ --accent-indigo: 242 25% 34%; /* hsl(242, 25%, 34%) */
@ -188,8 +188,8 @@
--tooltip: 0 0% 100%; /* hsl(0, 0%, 100%) */ --tooltip: 0 0% 100%; /* hsl(0, 0%, 100%) */
--tooltip-foreground: 0 0% 0%; /* hsl(0, 0%, 0%) */ --tooltip-foreground: 0 0% 0%; /* hsl(0, 0%, 0%) */
--error-red:0,75%,15%; /*hsla(0, 75%, 15%)*/ --error-red: 0, 75%, 15%; /*hsla(0, 75%, 15%)*/
--error-red-border: 0,70%,35%; /*hsla(0,70%,35%)*/ --error-red-border: 0, 70%, 35%; /*hsla(0,70%,35%)*/
--note-default: #0f172a; --note-default: #0f172a;
--note-indigo: #312e81; --note-indigo: #312e81;

View file

@ -124,6 +124,7 @@ import {
Palette, Palette,
PanelLeftClose, PanelLeftClose,
PanelLeftOpen, PanelLeftOpen,
PanelRightClose,
Paperclip, Paperclip,
PaperclipIcon, PaperclipIcon,
Pen, Pen,
@ -160,6 +161,7 @@ import {
Snowflake, Snowflake,
Sparkles, Sparkles,
Square, Square,
SquareArrowOutUpRight,
SquarePen, SquarePen,
SquarePlay, SquarePlay,
StickyNote, StickyNote,
@ -432,11 +434,6 @@ export const SIDEBAR_CATEGORIES = [
{ display_name: "Agents", name: "agents", icon: "Bot" }, { display_name: "Agents", name: "agents", icon: "Bot" },
{ display_name: "Chains", name: "chains", icon: "Link" }, { display_name: "Chains", name: "chains", icon: "Link" },
{ display_name: "Loaders", name: "documentloaders", icon: "Paperclip" }, { display_name: "Loaders", name: "documentloaders", icon: "Paperclip" },
{
display_name: "Utilities",
name: "langchain_utilities",
icon: "PocketKnife",
},
{ display_name: "Link Extractors", name: "link_extractors", icon: "Link2" }, { display_name: "Link Extractors", name: "link_extractors", icon: "Link2" },
{ display_name: "Memories", name: "memories", icon: "Cpu" }, { display_name: "Memories", name: "memories", icon: "Cpu" },
{ display_name: "Output Parsers", name: "output_parsers", icon: "Compass" }, { display_name: "Output Parsers", name: "output_parsers", icon: "Compass" },
@ -452,9 +449,9 @@ export const SIDEBAR_BUNDLES = [
{ display_name: "LangChain", name: "langchain_utilities", icon: "LangChain" }, { display_name: "LangChain", name: "langchain_utilities", icon: "LangChain" },
{ display_name: "AssemblyAI", name: "assemblyai", icon: "AssemblyAI" }, { display_name: "AssemblyAI", name: "assemblyai", icon: "AssemblyAI" },
{ {
display_name: "Astra Assistants", display_name: "DataStax",
name: "astra_assistants", name: "astra_assistants",
icon: "Sparkles", icon: "AstraDB",
}, },
{ display_name: "Google", name: "google", icon: "Google" }, { display_name: "Google", name: "google", icon: "Google" },
{ display_name: "Firecrawl", name: "firecrawl", icon: "FirecrawlCrawlApi" }, { display_name: "Firecrawl", name: "firecrawl", icon: "FirecrawlCrawlApi" },
@ -772,6 +769,7 @@ export const nodeIconsLucide: iconsType = {
Link, Link,
ToyBrick, ToyBrick,
RefreshCcw, RefreshCcw,
SquareArrowOutUpRight,
Combine, Combine,
TerminalIcon, TerminalIcon,
TerminalSquare, TerminalSquare,
@ -789,6 +787,7 @@ export const nodeIconsLucide: iconsType = {
Delete, Delete,
Command, Command,
ArrowBigUp, ArrowBigUp,
PanelRightClose,
Dot, Dot,
StickyNote, StickyNote,
note: StickyNote, note: StickyNote,

View file

@ -120,7 +120,6 @@ test("user must see on handle click the possibility connections - LLMChain", asy
await expect(page.getByTestId("disclosure-data")).toBeVisible(); await expect(page.getByTestId("disclosure-data")).toBeVisible();
await expect(page.getByTestId("disclosure-helpers")).toBeVisible(); await expect(page.getByTestId("disclosure-helpers")).toBeVisible();
await expect(page.getByTestId("disclosure-vector stores")).toBeVisible(); await expect(page.getByTestId("disclosure-vector stores")).toBeVisible();
await expect(page.getByTestId("disclosure-utilities")).toBeVisible();
await expect(page.getByTestId("disclosure-prototypes")).toBeVisible(); await expect(page.getByTestId("disclosure-prototypes")).toBeVisible();
await expect(page.getByTestId("disclosure-retrievers")).toBeVisible(); await expect(page.getByTestId("disclosure-retrievers")).toBeVisible();
await expect(page.getByTestId("disclosure-embeddings")).toBeVisible(); await expect(page.getByTestId("disclosure-embeddings")).toBeVisible();