- {getIcon(item.icon)}
+ {getAccountMenuOptionIcon(item.icon)}
{item.text}
@@ -165,7 +122,7 @@ export function ProfilePopoutMenu({
tabIndex={0}
>
- {getIcon(item.icon)}
+ {getAccountMenuOptionIcon(item.icon)}
{item.text}
diff --git a/autogpt_platform/frontend/src/components/agptui/ProfilePopoutMenuLogoutButton.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx
similarity index 90%
rename from autogpt_platform/frontend/src/components/agptui/ProfilePopoutMenuLogoutButton.tsx
rename to autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx
index fa4c8f955a..dc2c166797 100644
--- a/autogpt_platform/frontend/src/components/agptui/ProfilePopoutMenuLogoutButton.tsx
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/AccountMenu/components/AccountLogoutOption.tsx
@@ -1,14 +1,14 @@
"use client";
import { IconLogOut } from "@/components/ui/icons";
+import { LoadingSpinner } from "@/components/ui/loading";
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
import { cn } from "@/lib/utils";
import * as Sentry from "@sentry/nextjs";
import { useRouter } from "next/navigation";
import { useTransition } from "react";
-import { LoadingSpinner } from "../ui/loading";
-import { toast } from "../molecules/Toast/use-toast";
+import { toast } from "@/components/molecules/Toast/use-toast";
-export function ProfilePopoutMenuLogoutButton() {
+export function AccountLogoutOption() {
const router = useRouter();
const [isPending, startTransition] = useTransition();
const supabase = useSupabase();
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/LoginButton.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/LoginButton.tsx
new file mode 100644
index 0000000000..d060fcf4ad
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/LoginButton.tsx
@@ -0,0 +1,29 @@
+"use client";
+
+import { Button } from "@/components/atoms/Button/Button";
+import { SignInIcon } from "@phosphor-icons/react/dist/ssr";
+import { usePathname, useRouter } from "next/navigation";
+
+export function LoginButton() {
+ const router = useRouter();
+ const pathname = usePathname();
+ const isLoginPage = pathname.includes("/login");
+
+ if (isLoginPage) return null;
+
+ function handleLogin() {
+ router.push("/login");
+ }
+
+ return (
+ }
+ variant="secondary"
+ >
+ Log In
+
+ );
+}
diff --git a/autogpt_platform/frontend/src/components/agptui/MobileNavBar.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/MobileNavBar.tsx
similarity index 62%
rename from autogpt_platform/frontend/src/components/agptui/MobileNavBar.tsx
rename to autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/MobileNavBar.tsx
index 447bddb88a..0053440251 100644
--- a/autogpt_platform/frontend/src/components/agptui/MobileNavBar.tsx
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/MobileNavBar.tsx
@@ -1,45 +1,26 @@
"use client";
-import * as React from "react";
-import Link from "next/link";
+import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { Button } from "@/components/ui/button";
import {
Popover,
- PopoverTrigger,
PopoverContent,
PopoverPortal,
+ PopoverTrigger,
} from "@/components/ui/popover";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Separator } from "@/components/ui/separator";
-import {
- IconType,
- IconMenu,
- IconChevronUp,
- IconEdit,
- IconLayoutDashboard,
- IconUploadCloud,
- IconSettings,
- IconLogOut,
- IconMarketplace,
- IconLibrary,
- IconBuilder,
-} from "../ui/icons";
import { AnimatePresence, motion } from "framer-motion";
-import { Button } from "@/components/ui/button";
import { usePathname } from "next/navigation";
+import * as React from "react";
+import { IconChevronUp, IconMenu } from "../../../../ui/icons";
+import { MenuItemGroup } from "../../helpers";
+import { MobileNavbarMenuItem } from "./components/MobileNavbarMenuItem";
interface MobileNavBarProps {
userName?: string;
userEmail?: string;
avatarSrc?: string;
- menuItemGroups: {
- groupName?: string;
- items: {
- icon: IconType;
- text: string;
- href?: string;
- onClick?: () => void;
- }[];
- }[];
+ menuItemGroups: MenuItemGroup[];
}
const Overlay = React.forwardRef(
@@ -49,76 +30,15 @@ const Overlay = React.forwardRef(
),
);
+
Overlay.displayName = "Overlay";
-const PopoutMenuItem: React.FC<{
- icon: IconType;
- isActive: boolean;
- text: React.ReactNode;
- href?: string;
- onClick?: () => void;
-}> = ({ icon, isActive, text, href, onClick }) => {
- const getIcon = (iconType: IconType) => {
- const iconClass = "w-6 h-6 relative";
- switch (iconType) {
- case IconType.Marketplace:
- return
;
- case IconType.Library:
- return
;
- case IconType.Builder:
- return
;
- case IconType.Edit:
- return
;
- case IconType.LayoutDashboard:
- return
;
- case IconType.UploadCloud:
- return
;
- case IconType.Settings:
- return
;
- case IconType.LogOut:
- return
;
- default:
- return null;
- }
- };
-
- const content = (
-
- {getIcon(icon)}
-
-
- {text}
-
- {isActive && (
-
- )}
-
-
- );
-
- if (onClick)
- return (
-
- {content}
-
- );
- if (href)
- return (
-
- {content}
-
- );
- return content;
-};
-
-export const MobileNavBar: React.FC
= ({
+export function MobileNavBar({
userName,
userEmail,
avatarSrc,
menuItemGroups,
-}) => {
+}: MobileNavBarProps) {
const [isOpen, setIsOpen] = React.useState(false);
const pathname = usePathname();
const parts = pathname.split("/");
@@ -173,7 +93,7 @@ export const MobileNavBar: React.FC = ({
{menuItemGroups.map((group, groupIndex) => (
{group.items.map((item, itemIndex) => (
- = ({
);
-};
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/components/MobileNavbarMenuItem.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/components/MobileNavbarMenuItem.tsx
new file mode 100644
index 0000000000..e4955946a3
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/MobileNavbar/components/MobileNavbarMenuItem.tsx
@@ -0,0 +1,55 @@
+import { IconType } from "@/components/ui/icons";
+import { cn } from "@/lib/utils";
+import Link from "next/link";
+import { getAccountMenuOptionIcon } from "../../../helpers";
+
+interface Props {
+ icon: IconType;
+ isActive: boolean;
+ text: string;
+ href?: string;
+ onClick?: () => void;
+}
+
+export function MobileNavbarMenuItem({
+ icon,
+ isActive,
+ text,
+ href,
+ onClick,
+}: Props) {
+ const content = (
+
+ {getAccountMenuOptionIcon(icon)}
+
+
+ {text}
+
+ {isActive && (
+
+ )}
+
+
+ );
+
+ if (onClick)
+ return (
+
+ {content}
+
+ );
+ if (href)
+ return (
+
+ {content}
+
+ );
+ return content;
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLink.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLink.tsx
new file mode 100644
index 0000000000..0f795689a3
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLink.tsx
@@ -0,0 +1,68 @@
+"use client";
+
+import { IconLaptop } from "@/components/ui/icons";
+import { cn } from "@/lib/utils";
+import {
+ CubeIcon,
+ HouseIcon,
+ StorefrontIcon,
+} from "@phosphor-icons/react/dist/ssr";
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+import { Text } from "../../../atoms/Text/Text";
+
+interface Props {
+ name: string;
+ href: string;
+}
+
+export function NavbarLink({ name, href }: Props) {
+ const pathname = usePathname();
+ const isActive = pathname.includes(href);
+
+ return (
+
+
+ {href === "/marketplace" && (
+
+ )}
+ {href === "/build" && (
+
+ )}
+ {href === "/monitor" && (
+
+ )}
+ {href === "/library" && (
+
+ )}
+
+ {name}
+
+
+
+ );
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx
new file mode 100644
index 0000000000..6aa6252b77
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarLoading.tsx
@@ -0,0 +1,21 @@
+import { IconAutoGPTLogo } from "@/components/ui/icons";
+import { Skeleton } from "@/components/ui/skeleton";
+
+export function NavbarLoading() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/data.ts b/autogpt_platform/frontend/src/components/layout/Navbar/data.ts
new file mode 100644
index 0000000000..f7f79737dc
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/data.ts
@@ -0,0 +1,29 @@
+import { getV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/store";
+import { getServerUser } from "@/lib/supabase/server/getServerUser";
+
+export async function getNavbarAccountData() {
+ const { user } = await getServerUser();
+ const isLoggedIn = Boolean(user);
+
+ if (!isLoggedIn) {
+ return {
+ profile: null,
+ isLoggedIn,
+ };
+ }
+
+ let profile = null;
+
+ try {
+ const profileResponse = await getV2GetUserProfile();
+ profile = profileResponse.data || null;
+ } catch (error) {
+ console.error("Error fetching profile:", error);
+ profile = null;
+ }
+
+ return {
+ profile,
+ isLoggedIn,
+ };
+}
diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/helpers.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/helpers.tsx
new file mode 100644
index 0000000000..d2ef1bc241
--- /dev/null
+++ b/autogpt_platform/frontend/src/components/layout/Navbar/helpers.tsx
@@ -0,0 +1,115 @@
+import {
+ IconBuilder,
+ IconEdit,
+ IconLayoutDashboard,
+ IconLibrary,
+ IconLogOut,
+ IconMarketplace,
+ IconRefresh,
+ IconSettings,
+ IconType,
+ IconUploadCloud,
+} from "@/components/ui/icons";
+
+type Link = {
+ name: string;
+ href: string;
+};
+
+export const loggedInLinks: Link[] = [
+ {
+ name: "Marketplace",
+ href: "/marketplace",
+ },
+ {
+ name: "Library",
+ href: "/library",
+ },
+ {
+ name: "Build",
+ href: "/build",
+ },
+];
+
+export const loggedOutLinks: Link[] = [
+ {
+ name: "Marketplace",
+ href: "/marketplace",
+ },
+];
+
+export type MenuItemGroup = {
+ groupName?: string;
+ items: {
+ icon: IconType;
+ text: string;
+ href?: string;
+ onClick?: () => void;
+ }[];
+};
+
+export const accountMenuItems: MenuItemGroup[] = [
+ {
+ items: [
+ {
+ icon: IconType.Edit,
+ text: "Edit profile",
+ href: "/profile",
+ },
+ ],
+ },
+ {
+ items: [
+ {
+ icon: IconType.LayoutDashboard,
+ text: "Creator Dashboard",
+ href: "/profile/dashboard",
+ },
+ {
+ icon: IconType.UploadCloud,
+ text: "Publish an agent",
+ },
+ ],
+ },
+ {
+ items: [
+ {
+ icon: IconType.Settings,
+ text: "Settings",
+ href: "/profile/settings",
+ },
+ ],
+ },
+ {
+ items: [
+ {
+ icon: IconType.LogOut,
+ text: "Log out",
+ },
+ ],
+ },
+];
+
+export function getAccountMenuOptionIcon(icon: IconType) {
+ const iconClass = "w-6 h-6";
+ switch (icon) {
+ case IconType.LayoutDashboard:
+ return ;
+ case IconType.UploadCloud:
+ return ;
+ case IconType.Edit:
+ return ;
+ case IconType.Settings:
+ return ;
+ case IconType.LogOut:
+ return ;
+ case IconType.Marketplace:
+ return ;
+ case IconType.Library:
+ return ;
+ case IconType.Builder:
+ return ;
+ default:
+ return ;
+ }
+}
diff --git a/autogpt_platform/frontend/src/components/styles/colors.ts b/autogpt_platform/frontend/src/components/styles/colors.ts
index 1a6616e3fd..24977ebca8 100644
--- a/autogpt_platform/frontend/src/components/styles/colors.ts
+++ b/autogpt_platform/frontend/src/components/styles/colors.ts
@@ -71,6 +71,30 @@ export const colors = {
800: "#0c5a29",
900: "#09441f",
},
+ purple: {
+ 50: "#f1ebfe",
+ 100: "#d5c0fc",
+ 200: "#c0a1fa",
+ 300: "#a476f8",
+ 400: "#925cf7",
+ 500: "#7733f5",
+ 600: "#6c2edf",
+ 700: "#5424ae",
+ 800: "#411c87",
+ 900: "#321567",
+ },
+ pink: {
+ 50: "#fdedf5",
+ 100: "#f9c6df",
+ 200: "#f6abd0",
+ 300: "#f284bb",
+ 400: "#f06dad",
+ 500: "#ec4899",
+ 600: "#d7428b",
+ 700: "#a8336d",
+ 800: "#822854",
+ 900: "#631e40",
+ },
// Special semantic colors
white: "#fefefe",
diff --git a/autogpt_platform/frontend/src/components/tokens/border-radius.stories.tsx b/autogpt_platform/frontend/src/components/tokens/border-radius.stories.tsx
index 10f1996a80..acf685a5a7 100644
--- a/autogpt_platform/frontend/src/components/tokens/border-radius.stories.tsx
+++ b/autogpt_platform/frontend/src/components/tokens/border-radius.stories.tsx
@@ -14,54 +14,54 @@ const meta: Meta = {
export default meta;
// Border radius scale data based on Figma design tokens
-// Custom naming convention: xs, s, m, l, xl, 2xl, full
+// Custom naming convention: xsmall, small, medium, large, xlarge, 2xlarge, full
const borderRadiusScale = [
{
- name: "xs",
+ name: "xsmall",
value: "0.25rem",
rem: "0.25rem",
px: "4px",
- class: "rounded-xs",
+ class: "rounded-xsmall",
description: "Extra small - for subtle rounding",
},
{
- name: "s",
+ name: "small",
value: "0.5rem",
rem: "0.5rem",
px: "8px",
- class: "rounded-s",
+ class: "rounded-small",
description: "Small - for cards and containers",
},
{
- name: "m",
+ name: "medium",
value: "0.75rem",
rem: "0.75rem",
px: "12px",
- class: "rounded-m",
+ class: "rounded-medium",
description: "Medium - for buttons and inputs",
},
{
- name: "l",
+ name: "large",
value: "1rem",
rem: "1rem",
px: "16px",
- class: "rounded-l",
+ class: "rounded-large",
description: "Large - for panels and modals",
},
{
- name: "xl",
+ name: "xlarge",
value: "1.25rem",
rem: "1.25rem",
px: "20px",
- class: "rounded-xl",
+ class: "rounded-xlarge",
description: "Extra large - for hero sections",
},
{
- name: "2xl",
+ name: "2xlarge",
value: "1.5rem",
rem: "1.5rem",
px: "24px",
- class: "rounded-2xl",
+ class: "rounded-2xlarge",
description: "2X large - for major containers",
},
{
@@ -84,10 +84,11 @@ export function AllVariants() {
Border Radius
- Our border radius system uses a simplified naming convention (xs, s,
- m, l, xl, 2xl, full) based on our Figma design tokens. This creates
- visual hierarchy and maintains design consistency across all
- components.
+ Our border radius system uses a descriptive naming convention
+ (xsmall, small, medium, large, xlarge, 2xlarge, full) based on our
+ Figma design tokens. This creates visual hierarchy and maintains
+ design consistency across all components while avoiding conflicts
+ with Tailwind's built-in classes.
@@ -137,9 +138,10 @@ export function AllVariants() {