-
+ {isModern ? (
+
+ ) : (
+
+ )}
+ {isModern &&
}
@@ -131,15 +169,30 @@ export function AppSidebar({ dynamicContent }: Props) {
)}
{isCollapsed && (
-
-
-
-
- Open sidebar
-
+
+ {isModern && (
+
+
+
+ )}
+
+
+ svg]:!size-4"
+ : "size-10 p-2 [&>svg]:!size-5",
+ )}
+ />
+
+ Open sidebar
+
+
)}
+ {/* Navigation links */}
@@ -175,6 +228,34 @@ export function AppSidebar({ dynamicContent }: Props) {
)}
+
+ {/* Footer: only in modern layout */}
+ {isModern && (
+
+ {!isCollapsed ? (
+
+ ) : (
+
+ )}
+
+ )}
);
}
diff --git a/autogpt_platform/frontend/src/components/layout/LayoutContext.tsx b/autogpt_platform/frontend/src/components/layout/LayoutContext.tsx
new file mode 100644
index 0000000000..2288c4a8a7
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/LayoutContext.tsx
@@ -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
({
+ layout: "modern",
+ setLayout: () => {},
+});
+
+export function LayoutProvider({ children }: { children: ReactNode }) {
+ const [layout, setLayoutState] = useState("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 (
+
+ {children}
+
+ );
+}
+
+export function useLayout() {
+ return useContext(LayoutContext);
+}
diff --git a/autogpt_platform/frontend/src/components/layout/LayoutSwitcher.tsx b/autogpt_platform/frontend/src/components/layout/LayoutSwitcher.tsx
new file mode 100644
index 0000000000..f838631f47
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/LayoutSwitcher.tsx
@@ -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 (
+
+ Layout
+
+
+ );
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx
index 0fd1842c7b..a9c7207c37 100644
--- a/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/Navbar.tsx
@@ -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 ;
+ return isClassic ? : null;
}
return (
<>
-
- {shouldShowPreviewBanner && previewBranchName ? (
-
- ) : null}
-
+ )}
+
+ {/* Modern layout: only preview banner + login for unauthenticated */}
+ {!isClassic && (
+ <>
+ {shouldShowPreviewBanner && previewBranchName ? (
+
+ ) : null}
+ {!isLoggedIn ? (
+
+
+
+ ) : null}
+ >
+ )}
+
+ {/* Mobile Navbar (both layouts) */}
{isLoggedIn && isSmallScreen ? (
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/AgentActivityDropdown.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/AgentActivityDropdown.tsx
index 1d120c3b09..6e537f4f05 100644
--- a/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/AgentActivityDropdown.tsx
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/AgentActivityDropdown.tsx
@@ -30,7 +30,7 @@ export function AgentActivityDropdown() {
data-testid="agent-activity-button"
aria-label="View Agent Activity"
>
-
+
{activeCount > 0 && (
<>
diff --git a/autogpt_platform/frontend/src/components/ui/sidebar.tsx b/autogpt_platform/frontend/src/components/ui/sidebar.tsx
index b1563de0ad..213a159bea 100644
--- a/autogpt_platform/frontend/src/components/ui/sidebar.tsx
+++ b/autogpt_platform/frontend/src/components/ui/sidebar.tsx
@@ -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";