fix layout of complete website

This commit is contained in:
Abhimanyu Yadav
2025-05-05 07:09:47 +05:30
parent 86cbd6edd1
commit 5d198e4fad
33 changed files with 159 additions and 349 deletions

View File

@@ -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>
</>
);
}

View File

@@ -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}

View File

@@ -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"

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,
)}
>

View File

@@ -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>

View File

@@ -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"),
},
};

View File

@@ -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>

View File

@@ -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>
);
};

View File

@@ -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",

View File

@@ -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,
)}
>

View File

@@ -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.",

View File

@@ -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"
>

View File

@@ -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">

View File

@@ -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: {

View File

@@ -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",

View File

@@ -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) => (

View File

@@ -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];

View File

@@ -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,

View File

@@ -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");
},
};

View File

@@ -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>

View File

@@ -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: [

View File

@@ -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: [

View File

@@ -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>
);
};

View File

@@ -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>
);

View File

@@ -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,

View File

@@ -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}

View File

@@ -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) => (

View File

@@ -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">

View File

@@ -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;

View File

@@ -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) => (

View File

@@ -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}