mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix layout of complete website
This commit is contained in:
@@ -63,7 +63,7 @@ export default function PlatformLayout({ children }: { children: ReactNode }) {
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<main className="w-full pt-8">{children}</main>
|
||||
<main className="w-full">{children}</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export default async function Page({
|
||||
<main className="mt-9 px-10">
|
||||
<BreadCrumbs items={breadcrumbs} />
|
||||
|
||||
<div className="mt-4 flex flex-col items-start gap-4 sm:mt-6 sm:gap-6 md:mt-8 md:flex-row md:gap-8">
|
||||
<div className="mt-4 flex flex-col items-start gap-4 sm:mt-6 sm:gap-6 md:mt-[3rem] md:flex-row md:gap-8">
|
||||
<div className="w-full md:w-auto md:shrink-0">
|
||||
<AgentInfo
|
||||
name={agent.agent_name}
|
||||
|
||||
@@ -150,22 +150,22 @@ export default async function Page({}: {}) {
|
||||
|
||||
return (
|
||||
<main>
|
||||
<section className="px-10">
|
||||
<section className="px-4 md:px-10">
|
||||
<HeroSection />
|
||||
</section>
|
||||
<FeaturedSection featuredAgents={featuredAgents.agents} />
|
||||
{/* 100px margin because our featured sections button are placed 40px below the container */}
|
||||
<section className="px-10">
|
||||
<Separator className="mb-6 mt-24" />
|
||||
<section className="px-4 md:px-10">
|
||||
{/* Below Separator's mt is 44px as per design; I need to add extra to counter the absolute positioning of the arrows above */}
|
||||
<Separator className="mb-6 mt-18" />
|
||||
<AgentsSection
|
||||
sectionTitle="Top Agents"
|
||||
agents={topAgents.agents as Agent[]}
|
||||
/>
|
||||
<Separator className="mb-[25px] mt-[60px]" />
|
||||
<Separator className="mb-6 mt-11" />
|
||||
<FeaturedCreators
|
||||
featuredCreators={featuredCreators.creators as FeaturedCreator[]}
|
||||
/>
|
||||
<Separator className="mb-[25px] mt-[60px]" />
|
||||
<Separator className="mb-6 mt-11" />
|
||||
<BecomeACreator
|
||||
title="Become a Creator"
|
||||
buttonText="Upload your agent"
|
||||
|
||||
@@ -127,7 +127,7 @@ function SearchResults({
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex-none">
|
||||
<SearchBar width="w-[439px]" height="h-[60px]" />
|
||||
<SearchBar className="w-[28rem]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-row gap-14 px-4 pr-10">
|
||||
<div className="flex flex-row gap-14 px-4 pr-10 pt-8">
|
||||
<Sidebar linkGroups={sidebarLinkGroups} />
|
||||
<div className="flex-1">{children}</div>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@ export default async function RootLayout({
|
||||
>
|
||||
<body
|
||||
className={cn(
|
||||
"mx-auto w-screen max-w-[1500px] overflow-x-hidden bg-white antialiased transition-colors",
|
||||
"bg-white antialiased transition-colors",
|
||||
inter.className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -9,6 +9,7 @@ import CredentialsProvider from "@/components/integrations/credentials-provider"
|
||||
import { LaunchDarklyProvider } from "@/components/feature-flag/feature-flag-provider";
|
||||
import OnboardingProvider from "@/components/onboarding/onboarding-provider";
|
||||
import { MockClientProps } from "@/lib/autogpt-server-api/mock_client";
|
||||
import PageStructureContainer from "@/components/page-structure-container-provider";
|
||||
|
||||
export interface ProvidersProps extends ThemeProviderProps {
|
||||
children: React.ReactNode;
|
||||
@@ -28,7 +29,9 @@ export function Providers({
|
||||
<CredentialsProvider>
|
||||
<LaunchDarklyProvider>
|
||||
<OnboardingProvider>
|
||||
<TooltipProvider>{children}</TooltipProvider>
|
||||
<TooltipProvider>
|
||||
<PageStructureContainer>{children}</PageStructureContainer>
|
||||
</TooltipProvider>
|
||||
</OnboardingProvider>
|
||||
</LaunchDarklyProvider>
|
||||
</CredentialsProvider>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { BecomeACreator } from "./BecomeACreator";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Become A Creator",
|
||||
title: "Agpt Custom ui/marketing/Become A Creator",
|
||||
component: BecomeACreator,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
@@ -15,7 +15,6 @@ const meta = {
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
title: { control: "text" },
|
||||
description: { control: "text" },
|
||||
buttonText: { control: "text" },
|
||||
onButtonClick: { action: "buttonClicked" },
|
||||
},
|
||||
@@ -26,9 +25,8 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
title: "Want to contribute?",
|
||||
description: "Join our ever-growing community of hackers and tinkerers",
|
||||
buttonText: "Become a Creator",
|
||||
title: "Become a Creator",
|
||||
buttonText: "Upload your agent",
|
||||
onButtonClick: () => console.log("Button clicked"),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ export const BecomeACreator: React.FC<BecomeACreatorProps> = ({
|
||||
return (
|
||||
<div className="mb-18 w-full sm:mb-36 md:mb-72">
|
||||
{/* Title */}
|
||||
<h2 className="mb-18 text-base font-medium text-zinc-500 dark:text-zinc-200">
|
||||
<h2 className="mb-18 font-poppins text-base font-medium text-zinc-500">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
|
||||
@@ -13,33 +13,23 @@ interface BreadCrumbsProps {
|
||||
|
||||
export const BreadCrumbs: React.FC<BreadCrumbsProps> = ({ items }) => {
|
||||
return (
|
||||
<div className="flex items-center gap-4">
|
||||
{/*
|
||||
Commented out for now, but keeping until we have approval to remove
|
||||
<button className="flex h-12 w-12 items-center justify-center rounded-full border border-neutral-200 transition-colors hover:bg-neutral-50 dark:border-neutral-700 dark:hover:bg-neutral-800">
|
||||
<IconLeftArrow className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
|
||||
</button>
|
||||
<button className="flex h-12 w-12 items-center justify-center rounded-full border border-neutral-200 transition-colors hover:bg-neutral-50 dark:border-neutral-700 dark:hover:bg-neutral-800">
|
||||
<IconRightArrow className="h-5 w-5 text-neutral-900 dark:text-neutral-100" />
|
||||
</button> */}
|
||||
<div className="flex h-auto flex-wrap items-center justify-start gap-2.5 dark:bg-transparent">
|
||||
{items.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<Link href={item.link}>
|
||||
<span className="rounded py-1 pr-2 font-sans text-base font-medium text-neutral-800 transition-colors duration-200 hover:text-neutral-400 dark:text-neutral-100 dark:hover:text-gray-500">
|
||||
{item.name.length > 50
|
||||
? `${item.name.slice(0, 50)}...`
|
||||
: item.name}
|
||||
</span>
|
||||
</Link>
|
||||
{index < items.length - 1 && (
|
||||
<span className="text-center font-sans text-base font-medium text-neutral-800 dark:text-neutral-100">
|
||||
/
|
||||
</span>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex h-auto flex-wrap items-center justify-start gap-2.5 dark:bg-transparent">
|
||||
{items.map((item, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<Link href={item.link}>
|
||||
<span className="rounded py-1 pr-2 font-sans text-base font-medium text-zinc-800 transition-colors duration-200 hover:text-zinc-400 dark:text-neutral-100 dark:hover:text-gray-500">
|
||||
{item.name.length > 50
|
||||
? `${item.name.slice(0, 50)}...`
|
||||
: item.name}
|
||||
</span>
|
||||
</Link>
|
||||
{index < items.length - 1 && (
|
||||
<span className="text-center font-sans text-base font-medium text-zinc-800 dark:text-zinc-100">
|
||||
/
|
||||
</span>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Chip } from "./Chip";
|
||||
|
||||
const meta: Meta<typeof Chip> = {
|
||||
component: Chip,
|
||||
title: "new/BasicBadge",
|
||||
title: "Agpt Custom ui/general/BasicBadge",
|
||||
argTypes: {
|
||||
children: {
|
||||
control: "text",
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Chip({
|
||||
return (
|
||||
<Badge
|
||||
className={cn(
|
||||
"rounded-[30px] border border-zinc-400 bg-white px-3.5 py-2 font-sans text-base font-normal text-zinc-600 shadow-none hover:border-zinc-500 hover:bg-zinc-100",
|
||||
"rounded-[30px] border border-zinc-400 bg-white px-3.5 py-2 text-center font-sans text-sm font-normal text-zinc-600 shadow-none hover:border-zinc-500 hover:bg-zinc-100 md:text-base",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { CreatorCard } from "./CreatorCard";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "new/Creator Card",
|
||||
title: "Agpt Custom ui/marketing/Creator Card",
|
||||
component: CreatorCard,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
@@ -19,7 +19,7 @@ const meta = {
|
||||
bio: { control: "text" },
|
||||
agentsUploaded: { control: "number" },
|
||||
onClick: { action: "clicked" },
|
||||
index: { control: "number" },
|
||||
key: { control: "number" },
|
||||
},
|
||||
} satisfies Meta<typeof CreatorCard>;
|
||||
|
||||
@@ -30,7 +30,7 @@ const defaultAvatarImage = "/default_avatar.png";
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
index: 0,
|
||||
key: 0,
|
||||
creatorName: "John Doe",
|
||||
creatorImage: defaultAvatarImage,
|
||||
bio: "AI enthusiast and developer with a passion for creating innovative agents.",
|
||||
@@ -41,7 +41,7 @@ export const Default: Story = {
|
||||
|
||||
export const NoImage: Story = {
|
||||
args: {
|
||||
index: 0,
|
||||
key: 0,
|
||||
creatorName: "John Doe",
|
||||
creatorImage: "",
|
||||
bio: "AI enthusiast and developer with a passion for creating innovative agents.",
|
||||
@@ -52,7 +52,7 @@ export const NoImage: Story = {
|
||||
|
||||
export const LongContent: Story = {
|
||||
args: {
|
||||
index: 1,
|
||||
key: 1,
|
||||
creatorName: "Alexandria Rodriguez-Fitzgerald Johnson III",
|
||||
creatorImage: defaultAvatarImage,
|
||||
bio: "Excited to start my journey in AI agent development! I have a background in computer science and machine learning, with a special interest in creating agents that can assist with everyday tasks and solve complex problems efficiently.",
|
||||
@@ -63,7 +63,7 @@ export const LongContent: Story = {
|
||||
|
||||
export const TestingInteractions: Story = {
|
||||
args: {
|
||||
index: 3,
|
||||
key: 3,
|
||||
creatorName: "Sam Brown",
|
||||
creatorImage: defaultAvatarImage,
|
||||
bio: "Exploring the frontiers of AI and its applications in everyday life.",
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import * as React from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
const BACKGROUND_COLORS = [
|
||||
"bg-amber-100 dark:bg-amber-800", // #fef3c7 / #92400e
|
||||
"bg-violet-100 dark:bg-violet-800", // #ede9fe / #5b21b6
|
||||
"bg-green-100 dark:bg-green-800", // #dcfce7 / #065f46
|
||||
"bg-blue-100 dark:bg-blue-800", // #dbeafe / #1e3a8a
|
||||
];
|
||||
|
||||
interface CreatorCardProps {
|
||||
creatorName: string;
|
||||
creatorImage: string;
|
||||
bio: string;
|
||||
agentsUploaded: number;
|
||||
onClick: () => void;
|
||||
index: number;
|
||||
key: number;
|
||||
}
|
||||
|
||||
export const CreatorCard: React.FC<CreatorCardProps> = ({
|
||||
@@ -23,13 +16,12 @@ export const CreatorCard: React.FC<CreatorCardProps> = ({
|
||||
bio,
|
||||
agentsUploaded,
|
||||
onClick,
|
||||
index,
|
||||
key,
|
||||
}) => {
|
||||
const backgroundColor = BACKGROUND_COLORS[index % BACKGROUND_COLORS.length];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`aspect-square w-80 space-y-4 rounded-3xl bg-amber-100 p-5 pt-6 hover:cursor-pointer hover:bg-amber-200`}
|
||||
key={key}
|
||||
className={`aspect-square w-full space-y-4 rounded-3xl bg-amber-100 p-5 pt-6 hover:cursor-pointer hover:bg-amber-200 sm:w-80`}
|
||||
onClick={onClick}
|
||||
data-testid="creator-card"
|
||||
>
|
||||
|
||||
@@ -27,7 +27,7 @@ export const FeaturedAgentCard: React.FC<FeaturedStoreCardProps> = ({
|
||||
data-testid="featured-store-card"
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className={`flex h-[30rem] w-full max-w-[27.5rem] flex-col hover:cursor-pointer md:w-[24rem] lg:w-[27.5rem] ${backgroundColor} rounded-[1.5rem] border-none px-5 pb-5 pt-6 transition-colors duration-200`}
|
||||
className={`flex h-[30rem] w-full min-w-[94vw] max-w-[27.5rem] flex-col hover:cursor-pointer md:w-[24rem] md:min-w-0 lg:w-[27.5rem] ${backgroundColor} rounded-[1.5rem] border-none px-5 pb-5 pt-6 transition-colors duration-200`}
|
||||
>
|
||||
<CardHeader className="mb-7 h-[9.5rem] space-y-3 p-0">
|
||||
<CardTitle className="line-clamp-3 font-poppins text-3xl font-medium text-zinc-800">
|
||||
|
||||
@@ -3,7 +3,7 @@ import { FeaturedAgentCard } from "./FeaturedAgentCard";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "new/Featured Store Card",
|
||||
title: "Agpt Custom UI/marketing/Featured Store Card",
|
||||
component: FeaturedAgentCard,
|
||||
parameters: {
|
||||
layout: {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { FilterChips } from "./FilterChips";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Filter Chips",
|
||||
title: "Agpt Custom UI/marketing/Filter Chips",
|
||||
component: FilterChips,
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
|
||||
@@ -48,7 +48,7 @@ export const Navbar = async ({ links, menuItemGroups }: NavbarProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<nav className="md:justify-center-center sticky top-0 z-40 hidden h-16 w-full border-b border-zinc-50 bg-neutral-50/20 px-4 backdrop-blur-[26px] md:flex md:items-center">
|
||||
<nav className="sticky top-0 z-40 hidden h-16 w-full border-b border-zinc-50 bg-neutral-50/20 px-4 backdrop-blur-[26px] md:flex md:items-center md:justify-center">
|
||||
{/* Nav Links */}
|
||||
<div className="flex flex-1 items-center gap-5">
|
||||
{links.map((link) => (
|
||||
|
||||
@@ -23,7 +23,10 @@ const icons = {
|
||||
|
||||
export const NavbarLink = ({ name, href }: NavbarLinkProps) => {
|
||||
const pathname = usePathname();
|
||||
const isActive = pathname === href;
|
||||
const isActive =
|
||||
href === "/marketplace"
|
||||
? pathname.includes("/marketplace")
|
||||
: pathname === href;
|
||||
|
||||
const Icon = icons[href as keyof typeof icons];
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ export const ProfileInfoForm = ({ profile }: { profile: CreatorDetails }) => {
|
||||
name="bio"
|
||||
defaultValue={profileData.description}
|
||||
placeholder="Tell us about yourself..."
|
||||
className="m-0 h-10 min-h-56 w-full resize-none rounded-3xl border border-zinc-300 bg-white py-2 pl-4 font-sans text-base font-normal text-zinc-800 shadow-none outline-none placeholder:text-zinc-400 focus:border-2 focus:border-[#CBD5E1] focus:shadow-none focus:ring-0"
|
||||
className="m-0 h-10 min-h-56 w-full resize-none rounded-3xl border border-[#E2E8F0] bg-white py-2 pl-4 font-sans text-base font-normal text-zinc-800 shadow-none outline-none ring-0 placeholder:text-zinc-400 focus:border-2 focus:border-[#CBD5E1] focus:shadow-none focus:ring-0"
|
||||
onChange={(e) => {
|
||||
const newProfileData = {
|
||||
...profileData,
|
||||
|
||||
@@ -3,28 +3,13 @@ import { SearchBar } from "./SearchBar";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Search Bar",
|
||||
title: "Agpt Custom ui/marketing/Search Bar",
|
||||
component: SearchBar,
|
||||
parameters: {
|
||||
nextjs: {
|
||||
appDirectory: true,
|
||||
navigation: {
|
||||
pathname: "/marketplace/search",
|
||||
query: {
|
||||
searchTerm: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
tags: ["autodocs"],
|
||||
argTypes: {
|
||||
placeholder: { control: "text" },
|
||||
backgroundColor: { control: "text" },
|
||||
iconColor: { control: "text" },
|
||||
textColor: { control: "text" },
|
||||
placeholderColor: { control: "text" },
|
||||
width: { control: "text" },
|
||||
height: { control: "text" },
|
||||
className: { control: "text" },
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
@@ -47,80 +32,25 @@ export const Default: Story = {
|
||||
export const CustomStyles: Story = {
|
||||
args: {
|
||||
placeholder: "Enter your search query",
|
||||
backgroundColor: "bg-blue-100",
|
||||
iconColor: "text-blue-500",
|
||||
textColor: "text-blue-700",
|
||||
placeholderColor: "text-blue-400",
|
||||
className: "bg-blue-100",
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomDimensions: Story = {
|
||||
args: {
|
||||
placeholder: "Custom size search bar",
|
||||
width: "w-full md:w-[30rem]",
|
||||
height: "h-[45px]",
|
||||
},
|
||||
};
|
||||
|
||||
export const DarkMode: Story = {
|
||||
args: {
|
||||
placeholder: "Dark mode search",
|
||||
backgroundColor: "bg-neutral-800",
|
||||
iconColor: "text-neutral-400",
|
||||
textColor: "text-neutral-200",
|
||||
placeholderColor: "text-neutral-400",
|
||||
},
|
||||
parameters: {
|
||||
backgrounds: { default: "dark" },
|
||||
},
|
||||
};
|
||||
|
||||
export const WithInteraction: Story = {
|
||||
export const TestingInteractions: Story = {
|
||||
args: {
|
||||
placeholder: "Type and press Enter",
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const input = canvas.getByTestId("store-search-input");
|
||||
|
||||
await userEvent.type(input, "test query");
|
||||
await userEvent.keyboard("{Enter}");
|
||||
|
||||
await expect(input).toHaveValue("test query");
|
||||
},
|
||||
};
|
||||
|
||||
export const EmptySubmit: Story = {
|
||||
args: {
|
||||
placeholder: "Empty submit test",
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const input = canvas.getByTestId("store-search-input");
|
||||
|
||||
await userEvent.click(input);
|
||||
await userEvent.keyboard("{Enter}");
|
||||
|
||||
await expect(input).toHaveValue("");
|
||||
},
|
||||
};
|
||||
|
||||
export const MobileViewCompact: Story = {
|
||||
args: {
|
||||
placeholder: "Search on mobile",
|
||||
width: "w-full",
|
||||
height: "h-[45px]",
|
||||
},
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "mobile1",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ExtraLongPlaceholder: Story = {
|
||||
args: {
|
||||
placeholder:
|
||||
"This is an extremely long placeholder text that demonstrates how the search bar handles overflow with very long placeholder text",
|
||||
// checking onChange in input
|
||||
const Input = canvas.getByTestId("store-search-input");
|
||||
await userEvent.type(Input, "test query", {
|
||||
delay: 100,
|
||||
});
|
||||
await userEvent.keyboard("{Enter}", {
|
||||
delay: 100,
|
||||
});
|
||||
await expect(Input).toHaveValue("test query");
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,26 +5,17 @@ import { useRouter } from "next/navigation";
|
||||
|
||||
import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
|
||||
import { Input } from "../ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface SearchBarProps {
|
||||
placeholder?: string;
|
||||
backgroundColor?: string;
|
||||
iconColor?: string;
|
||||
textColor?: string;
|
||||
placeholderColor?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** SearchBar component for user input and search functionality. */
|
||||
export const SearchBar: React.FC<SearchBarProps> = ({
|
||||
placeholder = 'Search for tasks like "optimise SEO"',
|
||||
backgroundColor = "bg-neutral-100 dark:bg-neutral-800",
|
||||
iconColor = "text-[#646464] dark:text-neutral-400",
|
||||
textColor = "text-[#707070] dark:text-neutral-200",
|
||||
placeholderColor = "text-[#707070] dark:text-neutral-400",
|
||||
width = "w-[100%] lg:w-[56.25rem]",
|
||||
height = "h-[60px]",
|
||||
className,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -32,7 +23,6 @@ export const SearchBar: React.FC<SearchBarProps> = ({
|
||||
|
||||
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
console.log(searchQuery);
|
||||
|
||||
if (searchQuery.trim()) {
|
||||
// Encode the search term and navigate to the desired path
|
||||
@@ -45,15 +35,18 @@ export const SearchBar: React.FC<SearchBarProps> = ({
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
data-testid="store-search-bar"
|
||||
className={`${width} ${height} px-4 pt-1 md:px-6 md:pt-1 ${backgroundColor} flex items-center justify-center gap-2 rounded-full md:gap-5`}
|
||||
className={cn(
|
||||
`flex h-14 w-full items-center justify-center gap-2 rounded-full bg-[#F3F3F3] px-6 py-2.5 md:h-18 md:gap-5`,
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<MagnifyingGlassIcon className={`h-5 w-5 md:h-7 md:w-7 ${iconColor}`} />
|
||||
<MagnifyingGlassIcon className={`h-5 w-5 text-[#020617] md:h-7 md:w-7`} />
|
||||
<Input
|
||||
type="text"
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
className={`flex-grow border-none bg-transparent ${textColor} p-0 font-sans text-lg font-normal leading-[2.25rem] tracking-tight md:text-xl placeholder:${placeholderColor} m-0 shadow-none focus:shadow-none focus:outline-none focus:ring-0`}
|
||||
className={`m-0 flex-grow border-none bg-transparent p-0 font-sans text-base font-normal text-zinc-800 shadow-none placeholder:text-neutral-500 focus:shadow-none focus:outline-none focus:ring-0 md:text-xl`}
|
||||
data-testid="store-search-input"
|
||||
/>
|
||||
</form>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { StoreCard } from "./StoreCard";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "new/StoreCard",
|
||||
title: "Agpt Custom ui/marketing/StoreCard",
|
||||
component: StoreCard,
|
||||
|
||||
decorators: [
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Agent, AgentsSection } from "./AgentsSection";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "new/Composite/Agents Section",
|
||||
title: "Agpt Custom UI/marketing/Agents Section",
|
||||
component: AgentsSection,
|
||||
|
||||
decorators: [
|
||||
|
||||
@@ -47,66 +47,32 @@ export const AgentsSection: React.FC<AgentsSectionProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex w-full flex-col items-center justify-center ${className}`}
|
||||
>
|
||||
<div className="w-full">
|
||||
<div
|
||||
className={`mb-9 pl-4 text-base font-medium text-zinc-500 dark:text-zinc-200 md:pl-0`}
|
||||
>
|
||||
{sectionTitle}
|
||||
<div className={`w-full space-y-9 ${className}`}>
|
||||
<h2 className="font-poppins text-base font-medium text-zinc-500">
|
||||
Top agents
|
||||
</h2>
|
||||
{!displayedAgents || displayedAgents.length === 0 ? (
|
||||
<div className="font-poppins text-gray-500 dark:text-gray-400">
|
||||
No agents found
|
||||
</div>
|
||||
{!displayedAgents || displayedAgents.length === 0 ? (
|
||||
<div className="font-poppins text-gray-500 dark:text-gray-400">
|
||||
No agents found
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* Mobile Carousel View */}
|
||||
<Carousel
|
||||
className="md:hidden"
|
||||
opts={{
|
||||
loop: true,
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{displayedAgents.map((agent, index) => (
|
||||
<CarouselItem key={index} className="min-w-64 max-w-71">
|
||||
<StoreCard
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
runs={agent.runs}
|
||||
rating={agent.rating}
|
||||
avatarSrc={agent.creator_avatar}
|
||||
creatorName={agent.creator}
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
</Carousel>
|
||||
|
||||
<div className="hidden grid-cols-1 place-items-center gap-5 md:grid md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4">
|
||||
{displayedAgents.map((agent, index) => (
|
||||
<StoreCard
|
||||
key={index}
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
runs={agent.runs}
|
||||
rating={agent.rating}
|
||||
avatarSrc={agent.creator_avatar}
|
||||
creatorName={agent.creator}
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 place-items-center gap-5 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4">
|
||||
{displayedAgents.map((agent, index) => (
|
||||
<StoreCard
|
||||
key={index}
|
||||
agentName={agent.agent_name}
|
||||
agentImage={agent.agent_image}
|
||||
description={agent.description}
|
||||
runs={agent.runs}
|
||||
rating={agent.rating}
|
||||
avatarSrc={agent.creator_avatar}
|
||||
creatorName={agent.creator}
|
||||
hideAvatar={hideAvatars}
|
||||
onClick={() => handleCardClick(agent.creator, agent.slug)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -31,25 +31,22 @@ export const FeaturedCreators: React.FC<FeaturedCreatorsProps> = ({
|
||||
const displayedCreators = featuredCreators.slice(0, 4);
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center justify-center">
|
||||
<div className="w-full">
|
||||
<h2 className="mb-9 text-base font-medium text-zinc-500 dark:text-zinc-200">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="w-full space-y-9">
|
||||
<h2 className="text-base font-medium text-zinc-500 dark:text-zinc-200">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-wrap gap-5">
|
||||
{displayedCreators.map((creator, index) => (
|
||||
<CreatorCard
|
||||
key={index}
|
||||
creatorName={creator.name || creator.username}
|
||||
creatorImage={creator.avatar_url}
|
||||
bio={creator.description}
|
||||
agentsUploaded={creator.num_agents}
|
||||
onClick={() => handleCardClick(creator.username)}
|
||||
index={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-5">
|
||||
{displayedCreators.map((creator, index) => (
|
||||
<CreatorCard
|
||||
key={index}
|
||||
creatorName={creator.name || creator.username}
|
||||
creatorImage={creator.avatar_url}
|
||||
bio={creator.description}
|
||||
agentsUploaded={creator.num_agents}
|
||||
onClick={() => handleCardClick(creator.username)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,21 +4,11 @@ import { userEvent, within, expect } from "@storybook/test";
|
||||
import { StoreAgent } from "@/lib/autogpt-server-api";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Composite/Featured Agents",
|
||||
title: "Agpt Custom UI/marketing/Featured Agents",
|
||||
component: FeaturedSection,
|
||||
parameters: {
|
||||
layout: {
|
||||
center: true,
|
||||
fullscreen: true,
|
||||
padding: 0,
|
||||
},
|
||||
viewport: {
|
||||
defaultViewport: "responsive",
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="flex items-center justify-center py-4 pl-4">
|
||||
<div className="flex items-center justify-center py-4">
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
@@ -123,40 +113,6 @@ export const NoAgents: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithMissingData: Story = {
|
||||
args: {
|
||||
featuredAgents: [
|
||||
{
|
||||
...mockFeaturedAgents[0],
|
||||
sub_heading: "",
|
||||
agent_image: "",
|
||||
creator_avatar: "",
|
||||
},
|
||||
mockFeaturedAgents[1],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const WithExtremelyLongTexts: Story = {
|
||||
args: {
|
||||
featuredAgents: [
|
||||
{
|
||||
...mockFeaturedAgents[0],
|
||||
agent_name:
|
||||
"Universal Language Translator Pro with Advanced Neural Network Technology and Cross-Cultural Communication Capabilities for International Business and Education with Extended Support for Rare Dialects",
|
||||
sub_heading:
|
||||
"Breaking language barriers with cutting-edge AI translation technology that revolutionizes global communication for businesses and individuals across continents while preserving cultural nuances and contextual meanings in more than 150 languages including endangered dialects and specialized terminology",
|
||||
description:
|
||||
"Experience seamless communication across 150+ languages with our advanced neural translation engine. Perfect for international businesses, travelers, and language enthusiasts. Features real-time conversation translation, document processing, and cultural context adaptation to ensure your message is delivered exactly as intended in any language. Our proprietary machine learning algorithms continuously improve translation accuracy with each interaction, adapting to regional dialects and specialized terminology. The system includes voice recognition capabilities, image-to-text translation for signs and documents, and can operate offline in emergency situations where internet connectivity is limited. With dedicated mobile apps for iOS and Android plus browser extensions, you'll never encounter language barriers again, whether in business negotiations, academic research, or while exploring new destinations.",
|
||||
creator:
|
||||
"Global Linguistics Technologies International Corporation and Research Institute for Cross-Cultural Communication",
|
||||
runs: 999999999999,
|
||||
},
|
||||
mockFeaturedAgents[1],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const WithManyAgents: Story = {
|
||||
args: {
|
||||
featuredAgents: Array(20)
|
||||
@@ -169,44 +125,6 @@ export const WithManyAgents: Story = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithInvalidImageURLs: Story = {
|
||||
args: {
|
||||
featuredAgents: [
|
||||
{
|
||||
...mockFeaturedAgents[0],
|
||||
agent_image: "https://invalid-url.jpg",
|
||||
creator_avatar: "https://another-invalid-url.jpg",
|
||||
},
|
||||
mockFeaturedAgents[1],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const WithSpecialCharacters: Story = {
|
||||
args: {
|
||||
featuredAgents: [
|
||||
{
|
||||
...mockFeaturedAgents[0],
|
||||
agent_name: "Special &<>\"'/ Characters",
|
||||
creator: "User with @#$%^&*()_+{}[]",
|
||||
slug: "special-characters!@#$%",
|
||||
},
|
||||
mockFeaturedAgents[1],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const MobileView: Story = {
|
||||
args: {
|
||||
featuredAgents: mockFeaturedAgents,
|
||||
},
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: "mobile2",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithCardInteraction: Story = {
|
||||
args: {
|
||||
featuredAgents: mockFeaturedAgents,
|
||||
|
||||
@@ -46,8 +46,8 @@ export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="w-full space-y-8">
|
||||
<h2 className="pl-10 font-poppins text-base font-medium text-zinc-500">
|
||||
<section className="w-full space-y-7">
|
||||
<h2 className="pl-4 font-poppins text-base font-medium text-zinc-500 md:pl-10">
|
||||
Featured agents
|
||||
</h2>
|
||||
|
||||
@@ -61,7 +61,7 @@ export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
|
||||
{featuredAgents.map((agent, index) => (
|
||||
<CarouselItem
|
||||
key={index}
|
||||
className={`w-fit flex-none ${index === featuredAgents.length - 1 ? "mr-4" : ""} ${index === 0 ? "pl-14" : ""}`}
|
||||
className={`flex w-screen flex-none items-center justify-center md:w-fit ${index === featuredAgents.length - 1 ? "md:mr-4" : ""} ${index === 0 ? "pl-8 md:pl-14" : ""}`}
|
||||
>
|
||||
<Link
|
||||
href={`/marketplace/agent/${encodeURIComponent(agent.creator)}/${encodeURIComponent(agent.slug)}`}
|
||||
@@ -75,7 +75,7 @@ export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<div className="relative mt-4 px-10">
|
||||
<div className="relative mt-4 px-4 md:px-10">
|
||||
<CarouselIndicator />
|
||||
<CarouselPrevious
|
||||
afterClick={handlePrevSlide}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { HeroSection } from "./HeroSection";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Composite/Hero Section",
|
||||
title: "Agpt Custom UI/marketing/Hero Section",
|
||||
component: HeroSection,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
|
||||
@@ -21,9 +21,9 @@ export const HeroSection: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex w-[90%] flex-col items-center justify-center pb-12 pt-16 md:w-full md:pb-28 md:pt-32">
|
||||
<div className="mx-auto flex w-full flex-col items-center justify-center pb-20 pt-6 md:w-full md:pb-32 md:pt-36">
|
||||
{/* Title */}
|
||||
<h1 className="mb-4 text-center font-poppins text-2xl font-semibold leading-8 text-zinc-900 md:mb-9 md:text-[2.75rem] md:leading-[3.5rem]">
|
||||
<h1 className="mb-4 text-center font-poppins text-3xl font-semibold leading-8 text-zinc-900 md:mb-8 md:text-[2.75rem] md:leading-[3.5rem]">
|
||||
<span>Explore AI agents built for </span>
|
||||
<span className="text-violet-600">you</span>
|
||||
<br />
|
||||
@@ -32,12 +32,12 @@ export const HeroSection: React.FC = () => {
|
||||
</h1>
|
||||
|
||||
{/* Description */}
|
||||
<h3 className="mb-6 text-center font-sans text-lg text-zinc-600 md:mb-12 md:text-xl">
|
||||
<h3 className="mb-6 text-center font-sans text-base text-zinc-600 md:mb-12 md:text-xl">
|
||||
Bringing you AI agents designed by thinkers from around the world
|
||||
</h3>
|
||||
|
||||
{/* Seach bar */}
|
||||
<SearchBar height="h-14 md:h-18" />
|
||||
<SearchBar className="max-w-4xl" />
|
||||
|
||||
{/* Filter chips */}
|
||||
<div className="mt-5">
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
"use client";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
interface ProfileColorContainerProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const PageStructureContainer: React.FC<ProfileColorContainerProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
const pathname = usePathname();
|
||||
const isProfilePage = pathname?.includes("/profile") || false;
|
||||
|
||||
return (
|
||||
<div className={`${isProfilePage ? "bg-zinc-50" : "bg-white"}`}>
|
||||
<div className="mx-auto max-w-[1500px]">{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageStructureContainer;
|
||||
@@ -213,7 +213,7 @@ const CarouselPrevious = React.forwardRef<
|
||||
className={cn(
|
||||
"pointer absolute h-10 w-10 rounded-full border border-zinc-700 bg-white text-zinc-800 hover:bg-zinc-800 hover:text-white",
|
||||
orientation === "horizontal"
|
||||
? "right-24 top-0"
|
||||
? "right-18 top-0 md:right-24"
|
||||
: "-top-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className,
|
||||
)}
|
||||
@@ -259,7 +259,7 @@ const CarouselNext = React.forwardRef<
|
||||
className={cn(
|
||||
"order absolute h-10 w-10 rounded-full border-zinc-700 bg-white text-zinc-800 hover:bg-zinc-800 hover:text-white",
|
||||
orientation === "horizontal"
|
||||
? "right-12 top-0"
|
||||
? "right-6 top-0 md:right-12"
|
||||
: "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
|
||||
className,
|
||||
)}
|
||||
@@ -302,7 +302,7 @@ const CarouselIndicator = React.forwardRef<
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn("relative top-7 flex h-3 items-center gap-2", className)}
|
||||
className={cn("relative top-3.5 flex h-3 items-center gap-2", className)}
|
||||
{...props}
|
||||
>
|
||||
{scrollSnaps.map((_, index) => (
|
||||
|
||||
@@ -10,7 +10,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"agpt-border-input flex min-h-[80px] w-full rounded-md border bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"agpt-border-input flex min-h-[80px] w-full rounded-md border bg-background px-3 py-2 text-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
|
||||
Reference in New Issue
Block a user