mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-30 03:00:41 -04:00
testing-update: add layout switcher with classic/modern sidebar variants
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
import { AppSidebar } from "@/components/layout/AppSidebar/AppSidebar";
|
||||
import { SidebarDynamicContent } from "@/components/layout/AppSidebar/SidebarDynamicContent";
|
||||
import { LayoutProvider } from "@/components/layout/LayoutContext";
|
||||
import { LayoutSwitcher } from "@/components/layout/LayoutSwitcher";
|
||||
import { Navbar } from "@/components/layout/Navbar/Navbar";
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { NetworkStatusMonitor } from "@/services/network-status/NetworkStatusMonitor";
|
||||
@@ -18,16 +20,19 @@ export default function PlatformLayout({ children }: { children: ReactNode }) {
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<SidebarProvider defaultOpen={true}>
|
||||
<AppSidebar dynamicContent={<SidebarDynamicContent />} />
|
||||
<main className="flex h-screen w-full flex-col overflow-hidden">
|
||||
<NetworkStatusMonitor />
|
||||
<Navbar />
|
||||
<AdminImpersonationBanner />
|
||||
<section ref={scrollRef} className="flex-1 overflow-y-auto">
|
||||
{children}
|
||||
</section>
|
||||
</main>
|
||||
</SidebarProvider>
|
||||
<LayoutProvider>
|
||||
<SidebarProvider defaultOpen={true}>
|
||||
<AppSidebar dynamicContent={<SidebarDynamicContent />} />
|
||||
<main className="flex h-screen w-full flex-col overflow-hidden">
|
||||
<NetworkStatusMonitor />
|
||||
<Navbar />
|
||||
<AdminImpersonationBanner />
|
||||
<section ref={scrollRef} className="flex-1 overflow-y-auto">
|
||||
{children}
|
||||
</section>
|
||||
</main>
|
||||
<LayoutSwitcher />
|
||||
</SidebarProvider>
|
||||
</LayoutProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1709,6 +1709,67 @@ export const IconMoon = createIcon((props) => (
|
||||
* @param {IconProps} props - The props object containing additional attributes and event handlers for the icon.
|
||||
* @returns {JSX.Element} - The AutoGPT logo icon.
|
||||
*/
|
||||
/**
|
||||
* Minimal octopus-only variant of the AutoGPT logo (no "Auto" text).
|
||||
*/
|
||||
export const IconAutoGPTLogoMinimal = createIcon((props) => (
|
||||
<svg
|
||||
width="42"
|
||||
height="40"
|
||||
viewBox="47 0 42 40"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-label="AutoGPT Logo"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M69.1364 28.8681V38.6414C69.1364 39.3617 68.5471 39.951 67.8301 39.951C67.0541 39.951 66.4124 39.4599 66.4124 38.6414V24.0584C66.4124 20.9644 68.9236 18.4531 72.0177 18.4531C75.1117 18.4531 77.623 20.9644 77.623 24.0584C77.623 27.1525 75.1117 29.6637 72.0177 29.6637C70.9634 29.6637 69.9812 29.3723 69.1397 28.8681H69.1364ZM70.2856 22.3231C71.2417 22.3231 72.0177 23.0991 72.0177 24.0552C72.0177 25.0112 71.2417 25.7872 70.2856 25.7872C70.1088 25.7872 69.9353 25.761 69.7749 25.7119C70.2824 26.3994 71.0976 26.8447 72.0177 26.8447C73.5565 26.8447 74.8039 25.5973 74.8039 24.0584C74.8039 22.5196 73.5565 21.2721 72.0177 21.2721C71.0976 21.2721 70.2824 21.7174 69.7749 22.405C69.9353 22.3559 70.1088 22.3297 70.2856 22.3297V22.3231Z"
|
||||
fill="url(#paint0_min)"
|
||||
/>
|
||||
<path
|
||||
d="M62.133 28.8675V35.144C62.133 35.7137 61.9005 36.2343 61.524 36.6075C60.6989 37.4326 59.1699 37.4326 58.3448 36.6075C57.2611 35.5238 58.2891 33.6903 56.3509 31.752C54.4126 29.8137 51.1974 29.8694 49.318 31.752C48.4504 32.6196 47.9102 33.8212 47.9102 35.144C47.9102 35.8643 48.4995 36.4536 49.2198 36.4536C49.999 36.4536 50.6375 35.9625 50.6375 35.144C50.6375 34.5743 50.87 34.057 51.2465 33.6805C52.0716 32.8554 53.6006 32.8554 54.4257 33.6805C55.6076 34.8624 54.4126 36.5289 56.4196 38.536C58.3022 40.4186 61.5731 40.4186 63.4524 38.536C64.3201 37.6683 64.8603 36.4667 64.8603 35.144V24.0545C64.8603 20.9605 62.3491 18.4492 59.255 18.4492C56.161 18.4492 53.6497 20.9605 53.6497 24.0545C53.6497 27.1486 56.161 29.6598 59.255 29.6598C60.3093 29.6598 61.2948 29.3684 62.133 28.8642V28.8675ZM59.255 26.8441C58.335 26.8441 57.5197 26.3988 57.0122 25.7112C57.1727 25.7603 57.3462 25.7865 57.523 25.7865C58.479 25.7865 59.255 25.0106 59.255 24.0545C59.255 23.0985 58.479 22.3225 57.523 22.3225C57.3462 22.3225 57.1727 22.3487 57.0122 22.3978C57.5197 21.7103 58.335 21.265 59.255 21.265C60.7938 21.265 62.0413 22.5124 62.0413 24.0512C62.0413 25.5901 60.7938 26.8375 59.255 26.8375V26.8441Z"
|
||||
fill="url(#paint1_min)"
|
||||
/>
|
||||
<path
|
||||
d="M81.709 12.959C81.709 9.51134 80.3371 6.24048 77.9045 3.80453C75.4685 1.36858 72.1977 0 68.75 0C65.3024 0 62.0315 1.37186 59.5956 3.80453C57.1596 6.24048 55.791 9.51461 55.791 12.959V13.5451C55.791 14.2948 56.4 14.9038 57.1498 14.9038C57.8996 14.9038 58.5085 14.2948 58.5085 13.5451V12.959C58.5085 10.2349 59.5956 7.64836 61.5175 5.72645C63.4394 3.80453 66.0259 2.71425 68.75 2.71425C71.4741 2.71425 74.0574 3.80126 75.9826 5.72645C77.9045 7.64836 78.9948 10.2349 78.9948 12.959C78.9948 13.7088 79.6037 14.3178 80.3535 14.3178C81.1033 14.3178 81.7123 13.7088 81.7123 12.959H81.709Z"
|
||||
fill="url(#paint2_min)"
|
||||
/>
|
||||
<path
|
||||
d="M81.7092 17.061V18.7341H83.8963C84.6232 18.7341 85.2191 19.33 85.2191 20.0569C85.2191 20.7837 84.6952 21.4582 83.8963 21.4582H81.7092V35.1964C81.7092 35.7661 81.9417 36.2834 82.3182 36.6599C83.1433 37.485 84.6723 37.485 85.4974 36.6599C85.8739 36.2834 86.1064 35.7661 86.1064 35.1964V34.738C86.1064 33.9228 86.7481 33.4284 87.5241 33.4284C88.2444 33.4284 88.8337 34.0177 88.8337 34.738V35.1964C88.8337 36.5192 88.2935 37.7208 87.4258 38.5884C85.5432 40.471 82.2822 40.471 80.3996 38.5884C79.5319 37.7208 78.9917 36.5192 78.9917 35.1964V17.061C78.9917 16.272 79.6171 15.7383 80.3832 15.7383C81.1493 15.7383 81.706 16.3342 81.706 17.061H81.7092Z"
|
||||
fill="url(#paint3_min)"
|
||||
/>
|
||||
<path
|
||||
d="M75.4293 38.6377C75.4293 39.358 74.8399 39.9441 74.1196 39.9441C73.3436 39.9441 72.7019 39.453 72.7019 38.6377V34.2013C72.7019 33.4809 73.2912 32.8916 74.0116 32.8916C74.7875 32.8916 75.4293 33.3827 75.4293 34.2013V38.6377Z"
|
||||
fill="url(#paint4_min)"
|
||||
/>
|
||||
<path
|
||||
d="M87.4713 32.257C88.2434 32.257 88.8693 31.6311 88.8693 30.859C88.8693 30.0869 88.2434 29.4609 87.4713 29.4609C86.6992 29.4609 86.0732 30.0869 86.0732 30.859C86.0732 31.6311 86.6992 32.257 87.4713 32.257Z"
|
||||
fill="#669CF6"
|
||||
/>
|
||||
<path
|
||||
d="M49.2167 39.9475C49.9888 39.9475 50.6147 39.3215 50.6147 38.5494C50.6147 37.7773 49.9888 37.1514 49.2167 37.1514C48.4445 37.1514 47.8186 37.7773 47.8186 38.5494C47.8186 39.3215 48.4445 39.9475 49.2167 39.9475Z"
|
||||
fill="#669CF6"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_min" x1="62.7328" y1="20.9589" x2="62.7328" y2="33.2932" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#000030" /><stop offset="1" stopColor="#9900FF" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_min" x1="47.5336" y1="20.947" x2="47.5336" y2="33.2951" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#000030" /><stop offset="1" stopColor="#4285F4" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_min" x1="69.4138" y1="6.17402" x2="48.0898" y2="-3.94009" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#4285F4" /><stop offset="1" stopColor="#9900FF" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_min" x1="74.2976" y1="15.7136" x2="74.2976" y2="34.5465" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#000030" /><stop offset="1" stopColor="#4285F4" />
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_min" x1="64.3579" y1="24.1914" x2="65.0886" y2="30.9756" gradientUnits="userSpaceOnUse">
|
||||
<stop stopColor="#4285F4" /><stop offset="1" stopColor="#9900FF" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
));
|
||||
|
||||
export const IconAutoGPTLogo = createIcon((props) => (
|
||||
<svg
|
||||
width="89"
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { IconAutoGPTLogo } from "@/components/__legacy__/ui/icons";
|
||||
import {
|
||||
IconAutoGPTLogo,
|
||||
IconAutoGPTLogoMinimal,
|
||||
} from "@/components/__legacy__/ui/icons";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarHeader,
|
||||
@@ -33,17 +37,40 @@ import {
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { ReactNode } from "react";
|
||||
import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store";
|
||||
import { okData } from "@/app/api/helpers";
|
||||
import { isLogoutInProgress } from "@/lib/autogpt-server-api/helpers";
|
||||
import { FeedbackButton } from "@/components/layout/Navbar/components/FeedbackButton";
|
||||
import { AgentActivityDropdown } from "@/components/layout/Navbar/components/AgentActivityDropdown/AgentActivityDropdown";
|
||||
import { AccountMenu } from "@/components/layout/Navbar/components/AccountMenu/AccountMenu";
|
||||
import { getAccountMenuItems } from "@/components/layout/Navbar/helpers";
|
||||
import { useLayout } from "@/components/layout/LayoutContext";
|
||||
|
||||
interface Props {
|
||||
dynamicContent?: ReactNode;
|
||||
}
|
||||
|
||||
export function AppSidebar({ dynamicContent }: Props) {
|
||||
const { layout } = useLayout();
|
||||
const { state } = useSidebar();
|
||||
const isCollapsed = state === "collapsed";
|
||||
const pathname = usePathname();
|
||||
const isChatEnabled = useGetFlag(Flag.CHAT);
|
||||
const { isLoggedIn } = useSupabase();
|
||||
const { user, isLoggedIn, isUserLoading } = useSupabase();
|
||||
const logoutInProgress = isLogoutInProgress();
|
||||
const dynamicMenuItems = getAccountMenuItems(user?.role);
|
||||
|
||||
const { data: profile, isLoading: isProfileLoading } =
|
||||
useGetV2GetUserProfile({
|
||||
query: {
|
||||
select: okData,
|
||||
enabled: isLoggedIn && !!user && !logoutInProgress,
|
||||
queryKey: ["/api/store/profile", user?.id],
|
||||
},
|
||||
});
|
||||
|
||||
const isLoadingProfile = isProfileLoading || isUserLoading;
|
||||
const isModern = layout === "modern";
|
||||
|
||||
const homeHref = isChatEnabled === true ? "/copilot" : "/library";
|
||||
|
||||
@@ -83,12 +110,16 @@ export function AppSidebar({ dynamicContent }: Props) {
|
||||
icon: Wrench,
|
||||
testId: "sidebar-link-build",
|
||||
},
|
||||
{
|
||||
name: "Settings",
|
||||
href: "/profile/settings",
|
||||
icon: GearSix,
|
||||
testId: "sidebar-link-settings",
|
||||
},
|
||||
...(!isModern
|
||||
? [
|
||||
{
|
||||
name: "Settings",
|
||||
href: "/profile/settings",
|
||||
icon: GearSix,
|
||||
testId: "sidebar-link-settings",
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
function isActive(href: string) {
|
||||
@@ -106,21 +137,28 @@ export function AppSidebar({ dynamicContent }: Props) {
|
||||
collapsible="icon"
|
||||
className="border-r border-zinc-100"
|
||||
>
|
||||
{/* Header */}
|
||||
<SidebarHeader
|
||||
className={cn(
|
||||
"!flex-row border-b border-zinc-100 px-3",
|
||||
isCollapsed
|
||||
? "items-center justify-center py-0"
|
||||
: "items-center py-0",
|
||||
isModern && (isCollapsed ? "py-3" : "py-3"),
|
||||
)}
|
||||
style={{ height: NAVBAR_HEIGHT_PX }}
|
||||
style={!isModern ? { height: NAVBAR_HEIGHT_PX } : undefined}
|
||||
>
|
||||
{!isCollapsed && (
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<Link href={homeHref}>
|
||||
<IconAutoGPTLogo className="h-8 w-24" />
|
||||
{isModern ? (
|
||||
<IconAutoGPTLogoMinimal className="h-8 w-8" />
|
||||
) : (
|
||||
<IconAutoGPTLogo className="h-8 w-24" />
|
||||
)}
|
||||
</Link>
|
||||
<div className="flex items-center gap-1">
|
||||
{isModern && <AgentActivityDropdown />}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<SidebarTrigger className="size-10 p-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&>svg]:!size-5" />
|
||||
@@ -131,15 +169,30 @@ export function AppSidebar({ dynamicContent }: Props) {
|
||||
</div>
|
||||
)}
|
||||
{isCollapsed && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<SidebarTrigger className="size-10 p-2 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground [&>svg]:!size-5" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Open sidebar</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className={cn(isModern && "flex flex-col items-center gap-2")}>
|
||||
{isModern && (
|
||||
<Link href={homeHref}>
|
||||
<IconAutoGPTLogoMinimal className="h-6 w-6" />
|
||||
</Link>
|
||||
)}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<SidebarTrigger
|
||||
className={cn(
|
||||
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
||||
isModern
|
||||
? "size-8 p-1.5 [&>svg]:!size-4"
|
||||
: "size-10 p-2 [&>svg]:!size-5",
|
||||
)}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">Open sidebar</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</SidebarHeader>
|
||||
|
||||
{/* Navigation links */}
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupContent>
|
||||
@@ -175,6 +228,34 @@ export function AppSidebar({ dynamicContent }: Props) {
|
||||
</SidebarGroup>
|
||||
)}
|
||||
</SidebarContent>
|
||||
|
||||
{/* Footer: only in modern layout */}
|
||||
{isModern && (
|
||||
<SidebarFooter className="border-t border-zinc-100 p-3">
|
||||
{!isCollapsed ? (
|
||||
<div className="flex items-center justify-between">
|
||||
<AccountMenu
|
||||
userName={profile?.username}
|
||||
userEmail={profile?.name}
|
||||
avatarSrc={profile?.avatar_url ?? ""}
|
||||
menuItemGroups={dynamicMenuItems}
|
||||
isLoading={isLoadingProfile}
|
||||
/>
|
||||
<FeedbackButton />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center gap-3">
|
||||
<AccountMenu
|
||||
userName={profile?.username}
|
||||
userEmail={profile?.name}
|
||||
avatarSrc={profile?.avatar_url ?? ""}
|
||||
menuItemGroups={dynamicMenuItems}
|
||||
isLoading={isLoadingProfile}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</SidebarFooter>
|
||||
)}
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext, useState, useEffect, ReactNode } from "react";
|
||||
|
||||
export type LayoutVariant = "classic" | "modern";
|
||||
|
||||
const STORAGE_KEY = "autogpt-layout-variant";
|
||||
|
||||
interface LayoutContextValue {
|
||||
layout: LayoutVariant;
|
||||
setLayout: (v: LayoutVariant) => void;
|
||||
}
|
||||
|
||||
const LayoutContext = createContext<LayoutContextValue>({
|
||||
layout: "modern",
|
||||
setLayout: () => {},
|
||||
});
|
||||
|
||||
export function LayoutProvider({ children }: { children: ReactNode }) {
|
||||
const [layout, setLayoutState] = useState<LayoutVariant>("modern");
|
||||
|
||||
useEffect(() => {
|
||||
const stored = localStorage.getItem(STORAGE_KEY) as LayoutVariant | null;
|
||||
if (stored === "classic" || stored === "modern") {
|
||||
setLayoutState(stored);
|
||||
}
|
||||
}, []);
|
||||
|
||||
function setLayout(v: LayoutVariant) {
|
||||
setLayoutState(v);
|
||||
localStorage.setItem(STORAGE_KEY, v);
|
||||
}
|
||||
|
||||
return (
|
||||
<LayoutContext.Provider value={{ layout, setLayout }}>
|
||||
{children}
|
||||
</LayoutContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useLayout() {
|
||||
return useContext(LayoutContext);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
"use client";
|
||||
|
||||
import { useLayout, LayoutVariant } from "./LayoutContext";
|
||||
|
||||
const OPTIONS: { value: LayoutVariant; label: string }[] = [
|
||||
{ value: "classic", label: "Classic" },
|
||||
{ value: "modern", label: "Modern" },
|
||||
];
|
||||
|
||||
export function LayoutSwitcher() {
|
||||
const { layout, setLayout } = useLayout();
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-4 left-1/2 z-50 flex -translate-x-1/2 items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-2 shadow-lg">
|
||||
<span className="text-xs font-medium text-zinc-500">Layout</span>
|
||||
<select
|
||||
value={layout}
|
||||
onChange={(e) => setLayout(e.target.value as LayoutVariant)}
|
||||
className="cursor-pointer rounded-md border border-zinc-200 bg-zinc-50 px-2 py-1 text-sm font-medium text-zinc-700 outline-none transition-colors hover:bg-zinc-100"
|
||||
>
|
||||
{OPTIONS.map((opt) => (
|
||||
<option key={opt.value} value={opt.value}>
|
||||
{opt.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -19,8 +19,10 @@ import { MobileNavBar } from "./components/MobileNavbar/MobileNavBar";
|
||||
import { NavbarLoading } from "./components/NavbarLoading";
|
||||
import { Wallet } from "./components/Wallet/Wallet";
|
||||
import { getAccountMenuItems, loggedInLinks } from "./helpers";
|
||||
import { useLayout } from "@/components/layout/LayoutContext";
|
||||
|
||||
export function Navbar() {
|
||||
const { layout } = useLayout();
|
||||
const { user, isLoggedIn, isUserLoading } = useSupabase();
|
||||
const breakpoint = useBreakpoint();
|
||||
const isSmallScreen = breakpoint === "sm" || breakpoint === "base";
|
||||
@@ -31,18 +33,17 @@ export function Navbar() {
|
||||
const previewBranchName = environment.getPreviewStealingDev();
|
||||
const logoutInProgress = isLogoutInProgress();
|
||||
|
||||
const { data: profile, isLoading: isProfileLoading } = useGetV2GetUserProfile(
|
||||
{
|
||||
const { data: profile, isLoading: isProfileLoading } =
|
||||
useGetV2GetUserProfile({
|
||||
query: {
|
||||
select: okData,
|
||||
enabled: isLoggedIn && !!user && !logoutInProgress,
|
||||
// Include user ID in query key to ensure cache invalidation when user changes
|
||||
queryKey: ["/api/store/profile", user?.id],
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const isLoadingProfile = isProfileLoading || isUserLoading;
|
||||
const isClassic = layout === "classic";
|
||||
|
||||
const shouldShowPreviewBanner = Boolean(isLoggedIn && previewBranchName);
|
||||
|
||||
@@ -55,45 +56,63 @@ export function Navbar() {
|
||||
];
|
||||
|
||||
if (isUserLoading) {
|
||||
return <NavbarLoading />;
|
||||
return isClassic ? <NavbarLoading /> : null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sticky top-0 z-40 w-full">
|
||||
{shouldShowPreviewBanner && previewBranchName ? (
|
||||
<PreviewBanner branchName={previewBranchName} />
|
||||
) : null}
|
||||
<nav
|
||||
className="relative inline-flex w-full items-center justify-end border-b border-zinc-100 bg-[#FAFAFA]/80 p-3 backdrop-blur-xl"
|
||||
style={{ height: NAVBAR_HEIGHT_PX }}
|
||||
>
|
||||
{isSidebarCollapsed && (
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<IconAutoGPTLogo className="h-8 w-24" />
|
||||
</div>
|
||||
)}
|
||||
{/* Right section */}
|
||||
{isLoggedIn && !isSmallScreen ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<FeedbackButton />
|
||||
<AgentActivityDropdown />
|
||||
{profile && <Wallet key={profile.username} />}
|
||||
<AccountMenu
|
||||
userName={profile?.username}
|
||||
userEmail={profile?.name}
|
||||
avatarSrc={profile?.avatar_url ?? ""}
|
||||
menuItemGroups={dynamicMenuItems}
|
||||
isLoading={isLoadingProfile}
|
||||
/>
|
||||
</div>
|
||||
) : !isLoggedIn ? (
|
||||
<LoginButton />
|
||||
{/* Classic layout: full top navbar */}
|
||||
{isClassic && (
|
||||
<div className="sticky top-0 z-40 w-full">
|
||||
{shouldShowPreviewBanner && previewBranchName ? (
|
||||
<PreviewBanner branchName={previewBranchName} />
|
||||
) : null}
|
||||
{/* <ThemeToggle /> */}
|
||||
</nav>
|
||||
</div>
|
||||
{/* Mobile Navbar - Adjust positioning */}
|
||||
<nav
|
||||
className="relative inline-flex w-full items-center justify-end border-b border-zinc-100 bg-[#FAFAFA]/80 p-3 backdrop-blur-xl"
|
||||
style={{ height: NAVBAR_HEIGHT_PX }}
|
||||
>
|
||||
{isSidebarCollapsed && (
|
||||
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||
<IconAutoGPTLogo className="h-8 w-24" />
|
||||
</div>
|
||||
)}
|
||||
{isLoggedIn && !isSmallScreen ? (
|
||||
<div className="flex items-center gap-4">
|
||||
<FeedbackButton />
|
||||
<AgentActivityDropdown />
|
||||
{profile && <Wallet key={profile.username} />}
|
||||
<AccountMenu
|
||||
userName={profile?.username}
|
||||
userEmail={profile?.name}
|
||||
avatarSrc={profile?.avatar_url ?? ""}
|
||||
menuItemGroups={dynamicMenuItems}
|
||||
isLoading={isLoadingProfile}
|
||||
/>
|
||||
</div>
|
||||
) : !isLoggedIn ? (
|
||||
<LoginButton />
|
||||
) : null}
|
||||
</nav>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Modern layout: only preview banner + login for unauthenticated */}
|
||||
{!isClassic && (
|
||||
<>
|
||||
{shouldShowPreviewBanner && previewBranchName ? (
|
||||
<div className="sticky top-0 z-40 w-full">
|
||||
<PreviewBanner branchName={previewBranchName} />
|
||||
</div>
|
||||
) : null}
|
||||
{!isLoggedIn ? (
|
||||
<div className="flex w-full justify-end p-3">
|
||||
<LoginButton />
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Mobile Navbar (both layouts) */}
|
||||
{isLoggedIn && isSmallScreen ? (
|
||||
<div className="fixed right-0 top-2 z-50 flex items-center gap-0">
|
||||
<Wallet />
|
||||
|
||||
@@ -30,7 +30,7 @@ export function AgentActivityDropdown() {
|
||||
data-testid="agent-activity-button"
|
||||
aria-label="View Agent Activity"
|
||||
>
|
||||
<Bell size={22} className="text-black" />
|
||||
<Bell size={20} className="text-black" />
|
||||
|
||||
{activeCount > 0 && (
|
||||
<>
|
||||
|
||||
@@ -27,8 +27,8 @@ import { SidebarSimpleIcon } from "@phosphor-icons/react";
|
||||
|
||||
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
||||
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
||||
const SIDEBAR_WIDTH = "16rem";
|
||||
const SIDEBAR_WIDTH_MOBILE = "16rem";
|
||||
const SIDEBAR_WIDTH = "18rem";
|
||||
const SIDEBAR_WIDTH_MOBILE = "18rem";
|
||||
const SIDEBAR_WIDTH_ICON = "3rem";
|
||||
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user