Update skyvern UI responsiveness (#1098)
Co-authored-by: Muhammed Salih Altun <muhammedsalihaltun@gmail.com>
This commit is contained in:
115
skyvern-frontend/src/components/ui/drawer.tsx
Normal file
115
skyvern-frontend/src/components/ui/drawer.tsx
Normal file
@@ -0,0 +1,115 @@
|
||||
import * as React from "react";
|
||||
import { Drawer as DrawerPrimitive } from "vaul";
|
||||
|
||||
import { cn } from "@/util/utils";
|
||||
|
||||
const Drawer = ({
|
||||
shouldScaleBackground = true,
|
||||
...props
|
||||
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
|
||||
<DrawerPrimitive.Root
|
||||
shouldScaleBackground={shouldScaleBackground}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
Drawer.displayName = "Drawer";
|
||||
|
||||
const DrawerTrigger = DrawerPrimitive.Trigger;
|
||||
|
||||
const DrawerPortal = DrawerPrimitive.Portal;
|
||||
|
||||
const DrawerClose = DrawerPrimitive.Close;
|
||||
|
||||
const DrawerOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn("fixed inset-0 z-50 bg-black/80", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
||||
|
||||
const DrawerContent = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DrawerPortal>
|
||||
<DrawerOverlay />
|
||||
<DrawerPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</DrawerPrimitive.Content>
|
||||
</DrawerPortal>
|
||||
));
|
||||
DrawerContent.displayName = "DrawerContent";
|
||||
|
||||
const DrawerHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DrawerHeader.displayName = "DrawerHeader";
|
||||
|
||||
const DrawerFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DrawerFooter.displayName = "DrawerFooter";
|
||||
|
||||
const DrawerTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
|
||||
|
||||
const DrawerDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DrawerPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DrawerPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Drawer,
|
||||
DrawerPortal,
|
||||
DrawerOverlay,
|
||||
DrawerTrigger,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerHeader,
|
||||
DrawerFooter,
|
||||
DrawerTitle,
|
||||
DrawerDescription,
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DiscordLogoIcon } from "@radix-ui/react-icons";
|
||||
import GitHubButton from "react-github-btn";
|
||||
import { Link, useMatch } from "react-router-dom";
|
||||
import { NavigationHamburgerMenu } from "./NavigationHamburgerMenu";
|
||||
|
||||
function Header() {
|
||||
const match = useMatch("/workflows/:workflowPermanentId/edit");
|
||||
@@ -11,24 +12,27 @@ function Header() {
|
||||
|
||||
return (
|
||||
<header>
|
||||
<div className="flex h-24 items-center justify-end gap-4 px-6">
|
||||
<Link
|
||||
to="https://discord.com/invite/fG2XXEuQX3"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<DiscordLogoIcon className="h-7 w-7" />
|
||||
</Link>
|
||||
<div className="h-7">
|
||||
<GitHubButton
|
||||
href="https://github.com/skyvern-ai/skyvern"
|
||||
data-color-scheme="no-preference: dark; light: dark; dark: dark;"
|
||||
data-size="large"
|
||||
data-show-count="true"
|
||||
aria-label="Star skyvern-ai/skyvern on GitHub"
|
||||
<div className="flex h-24 items-center px-6">
|
||||
<NavigationHamburgerMenu />
|
||||
<div className="ml-auto flex gap-4">
|
||||
<Link
|
||||
to="https://discord.com/invite/fG2XXEuQX3"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Star
|
||||
</GitHubButton>
|
||||
<DiscordLogoIcon className="h-7 w-7" />
|
||||
</Link>
|
||||
<div className="h-7">
|
||||
<GitHubButton
|
||||
href="https://github.com/skyvern-ai/skyvern"
|
||||
data-color-scheme="no-preference: dark; light: dark; dark: dark;"
|
||||
data-size="large"
|
||||
data-show-count="true"
|
||||
aria-label="Star skyvern-ai/skyvern on GitHub"
|
||||
>
|
||||
Star
|
||||
</GitHubButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
34
skyvern-frontend/src/routes/root/NavigationHamburgerMenu.tsx
Normal file
34
skyvern-frontend/src/routes/root/NavigationHamburgerMenu.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import {
|
||||
Drawer,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@/components/ui/drawer";
|
||||
import { HamburgerMenuIcon } from "@radix-ui/react-icons";
|
||||
import { SidebarContent } from "./SidebarContent";
|
||||
import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
|
||||
|
||||
function NavigationHamburgerMenu() {
|
||||
return (
|
||||
<div className="block lg:hidden">
|
||||
<Drawer direction="left">
|
||||
<DrawerTrigger asChild>
|
||||
<HamburgerMenuIcon className="size-6 cursor-pointer" />
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="bottom-2 left-2 top-2 mt-0 w-64 rounded border-0 px-6">
|
||||
<VisuallyHidden.Root>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Skyvern</DrawerTitle>
|
||||
<DrawerDescription>Skyvern App Navigation</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
</VisuallyHidden.Root>
|
||||
<SidebarContent />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { NavigationHamburgerMenu };
|
||||
@@ -1,59 +1,21 @@
|
||||
import { Link, Outlet } from "react-router-dom";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { SideNav } from "./SideNav";
|
||||
import { PinLeftIcon, PinRightIcon } from "@radix-ui/react-icons";
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { cn } from "@/util/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { LogoMinimized } from "@/components/LogoMinimized";
|
||||
import { Header } from "./Header";
|
||||
import { useSidebarStore } from "@/store/SidebarStore";
|
||||
import { cn } from "@/util/utils";
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { Header } from "./Header";
|
||||
import { Sidebar } from "./Sidebar";
|
||||
|
||||
function RootLayout() {
|
||||
const { collapsed, setCollapsed } = useSidebarStore();
|
||||
const collapsed = useSidebarStore((state) => state.collapsed);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full w-full">
|
||||
<aside
|
||||
className={cn("fixed h-screen min-h-screen border-r-2 px-6", {
|
||||
"w-64": !collapsed,
|
||||
"w-28": collapsed,
|
||||
})}
|
||||
>
|
||||
<div className="flex h-full flex-col">
|
||||
<Link to={window.location.origin}>
|
||||
<div className="flex h-24 items-center">
|
||||
{collapsed ? <LogoMinimized /> : <Logo />}
|
||||
</div>
|
||||
</Link>
|
||||
<SideNav collapsed={collapsed} />
|
||||
<div
|
||||
className={cn("mt-auto flex min-h-16", {
|
||||
"justify-center": collapsed,
|
||||
"justify-end": !collapsed,
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setCollapsed(!collapsed);
|
||||
}}
|
||||
>
|
||||
{collapsed ? (
|
||||
<PinRightIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<PinLeftIcon className="h-6 w-6" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<Sidebar />
|
||||
<Header />
|
||||
<main
|
||||
className={cn("pb-4 pl-64", {
|
||||
"pl-28": collapsed,
|
||||
className={cn("lg:pb-4 lg:pl-64", {
|
||||
"lg:pl-28": collapsed,
|
||||
})}
|
||||
>
|
||||
<Outlet />
|
||||
|
||||
23
skyvern-frontend/src/routes/root/Sidebar.tsx
Normal file
23
skyvern-frontend/src/routes/root/Sidebar.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useSidebarStore } from "@/store/SidebarStore";
|
||||
import { cn } from "@/util/utils";
|
||||
import { SidebarContent } from "./SidebarContent";
|
||||
|
||||
function Sidebar() {
|
||||
const collapsed = useSidebarStore((state) => state.collapsed);
|
||||
|
||||
return (
|
||||
<aside
|
||||
className={cn(
|
||||
"fixed hidden h-screen min-h-screen border-r-2 px-6 lg:block",
|
||||
{
|
||||
"w-64": !collapsed,
|
||||
"w-28": collapsed,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<SidebarContent useCollapsedState />
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
export { Sidebar };
|
||||
50
skyvern-frontend/src/routes/root/SidebarContent.tsx
Normal file
50
skyvern-frontend/src/routes/root/SidebarContent.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Logo } from "@/components/Logo";
|
||||
import { LogoMinimized } from "@/components/LogoMinimized";
|
||||
import { useSidebarStore } from "@/store/SidebarStore";
|
||||
import { Link } from "react-router-dom";
|
||||
import { SideNav } from "./SideNav";
|
||||
import { cn } from "@/util/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { PinLeftIcon, PinRightIcon } from "@radix-ui/react-icons";
|
||||
|
||||
type Props = {
|
||||
useCollapsedState?: boolean;
|
||||
};
|
||||
|
||||
function SidebarContent({ useCollapsedState }: Props) {
|
||||
const { collapsed: collapsedState, setCollapsed } = useSidebarStore();
|
||||
const collapsed = useCollapsedState ? collapsedState : false;
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<Link to={window.location.origin}>
|
||||
<div className="flex h-24 items-center">
|
||||
{collapsed ? <LogoMinimized /> : <Logo />}
|
||||
</div>
|
||||
</Link>
|
||||
<SideNav collapsed={collapsed} />
|
||||
<div
|
||||
className={cn("mt-auto flex min-h-16", {
|
||||
"justify-center": collapsed,
|
||||
"justify-end": !collapsed,
|
||||
})}
|
||||
>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setCollapsed(!collapsed);
|
||||
}}
|
||||
>
|
||||
{collapsed ? (
|
||||
<PinRightIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<PinLeftIcon className="hidden h-6 w-6 lg:block" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { SidebarContent };
|
||||
@@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom";
|
||||
|
||||
function SettingsPageLayout() {
|
||||
return (
|
||||
<div className="container mx-auto px-8">
|
||||
<div className="container mx-auto">
|
||||
<main>
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom";
|
||||
|
||||
function TasksPageLayout() {
|
||||
return (
|
||||
<div className="container mx-auto px-8">
|
||||
<div className="container mx-auto">
|
||||
<main>
|
||||
<Outlet />
|
||||
</main>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Outlet } from "react-router-dom";
|
||||
|
||||
function CreateNewTaskLayout() {
|
||||
return (
|
||||
<main className="container mx-auto px-8">
|
||||
<main className="container mx-auto">
|
||||
<Outlet />
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -149,7 +149,7 @@ function PromptBox() {
|
||||
<span className="text-2xl">
|
||||
What task would you like to accomplish?
|
||||
</span>
|
||||
<div className="flex w-[35rem] max-w-xl items-center rounded-xl bg-slate-700 py-2 pr-4">
|
||||
<div className="flex w-1/2 max-w-xl items-center rounded-xl bg-slate-700 py-2 pr-4">
|
||||
<Textarea
|
||||
className="min-h-0 resize-none rounded-xl border-transparent px-4 hover:border-transparent focus-visible:ring-0"
|
||||
value={prompt}
|
||||
|
||||
@@ -7,7 +7,7 @@ function WorkflowsPageLayout() {
|
||||
return (
|
||||
<main
|
||||
className={cn({
|
||||
"container mx-auto px-8": !match,
|
||||
"container mx-auto": !match,
|
||||
})}
|
||||
>
|
||||
<Outlet />
|
||||
|
||||
Reference in New Issue
Block a user