Skip to content

Commit ec00aa9

Browse files
authored
fix(frontend): agent favorites layout (#11733)
## Changes 🏗️ <img width="800" height="744" alt="Screenshot 2026-01-09 at 16 07 08" src="https://github.com/user-attachments/assets/034c97e2-18f3-441c-a13d-71f668ad672f" /> - Remove feature flag for agent favourites ( _keep it always visible_ ) - Fix the layout on the card so the ❤️ icon appears next to the `...` menu - Remove icons on toasts ## Checklist 📋 ### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Run the app locally and check the above <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Favorites now respond to the current search term and are available to all users (no feature-flag). * **UI/UX Improvements** * Redesigned Favorites section with simplified header, inline agent counts, updated spacing/dividers, and removal of skeleton placeholders. * Favorite button repositioned and visually simplified on agent cards. * Toast visuals simplified by removing per-type icons and adjusting close-button positioning. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 36fb1ea commit ec00aa9

File tree

8 files changed

+77
-87
lines changed

8 files changed

+77
-87
lines changed
Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,68 @@
11
"use client";
22

33
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
4-
import { Skeleton } from "@/components/__legacy__/ui/skeleton";
4+
import { Text } from "@/components/atoms/Text/Text";
55
import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteScroll";
6-
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
76
import { HeartIcon } from "@phosphor-icons/react";
87
import { useFavoriteAgents } from "../../hooks/useFavoriteAgents";
98
import { LibraryAgentCard } from "../LibraryAgentCard/LibraryAgentCard";
109

11-
export function FavoritesSection() {
12-
const isAgentFavoritingEnabled = useGetFlag(Flag.AGENT_FAVORITING);
10+
interface Props {
11+
searchTerm: string;
12+
}
13+
14+
export function FavoritesSection({ searchTerm }: Props) {
1315
const {
1416
allAgents: favoriteAgents,
1517
agentLoading: isLoading,
1618
agentCount,
1719
hasNextPage,
1820
fetchNextPage,
1921
isFetchingNextPage,
20-
} = useFavoriteAgents();
22+
} = useFavoriteAgents({ searchTerm });
2123

22-
// Only show this section if the feature flag is enabled
23-
if (!isAgentFavoritingEnabled) {
24-
return null;
25-
}
26-
27-
// Don't show the section if there are no favorites
28-
if (!isLoading && favoriteAgents.length === 0) {
24+
if (isLoading || favoriteAgents.length === 0) {
2925
return null;
3026
}
3127

3228
return (
33-
<div className="mb-8">
34-
<div className="flex items-center gap-[10px] p-2 pb-[10px]">
35-
<HeartIcon className="h-5 w-5 fill-red-500 text-red-500" />
36-
<span className="font-poppin text-[18px] font-semibold leading-[28px] text-neutral-800">
37-
Favorites
38-
</span>
39-
{!isLoading && (
40-
<span className="font-sans text-[14px] font-normal leading-6">
41-
{agentCount} {agentCount === 1 ? "agent" : "agents"}
42-
</span>
43-
)}
29+
<div className="!mb-8">
30+
<div className="mb-3 flex items-center gap-2 p-2">
31+
<HeartIcon className="h-5 w-5" weight="fill" />
32+
<div className="flex items-baseline gap-2">
33+
<Text variant="h4">Favorites</Text>
34+
{!isLoading && (
35+
<Text
36+
variant="body"
37+
data-testid="agents-count"
38+
className="relative bottom-px text-zinc-500"
39+
>
40+
{agentCount}
41+
</Text>
42+
)}
43+
</div>
4444
</div>
4545

4646
<div className="relative">
47-
{isLoading ? (
47+
<InfiniteScroll
48+
isFetchingNextPage={isFetchingNextPage}
49+
fetchNextPage={fetchNextPage}
50+
hasNextPage={hasNextPage}
51+
loader={
52+
<div className="flex h-8 w-full items-center justify-center">
53+
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-t-2 border-neutral-800" />
54+
</div>
55+
}
56+
>
4857
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
49-
{[...Array(4)].map((_, i) => (
50-
<Skeleton key={i} className="h-48 w-full rounded-lg" />
58+
{favoriteAgents.map((agent: LibraryAgent) => (
59+
<LibraryAgentCard key={agent.id} agent={agent} />
5160
))}
5261
</div>
53-
) : (
54-
<InfiniteScroll
55-
isFetchingNextPage={isFetchingNextPage}
56-
fetchNextPage={fetchNextPage}
57-
hasNextPage={hasNextPage}
58-
loader={
59-
<div className="flex h-8 w-full items-center justify-center">
60-
<div className="h-6 w-6 animate-spin rounded-full border-b-2 border-t-2 border-neutral-800" />
61-
</div>
62-
}
63-
>
64-
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
65-
{favoriteAgents.map((agent: LibraryAgent) => (
66-
<LibraryAgentCard key={agent.id} agent={agent} />
67-
))}
68-
</div>
69-
</InfiniteScroll>
70-
)}
62+
</InfiniteScroll>
7163
</div>
7264

73-
{favoriteAgents.length > 0 && <div className="mt-6 border-t pt-6" />}
65+
{favoriteAgents.length > 0 && <div className="!mt-10 border-t" />}
7466
</div>
7567
);
7668
}

autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/LibraryAgentCard.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export function LibraryAgentCard({ agent }: Props) {
2424

2525
const {
2626
isFromMarketplace,
27-
isAgentFavoritingEnabled,
2827
isFavorite,
2928
profile,
3029
creator_image_url,
@@ -37,9 +36,8 @@ export function LibraryAgentCard({ agent }: Props) {
3736
data-agent-id={id}
3837
className="group relative inline-flex h-[10.625rem] w-full max-w-[25rem] flex-col items-start justify-start gap-2.5 rounded-medium border border-zinc-100 bg-white transition-all duration-300 hover:shadow-md"
3938
>
40-
<AgentCardMenu agent={agent} />
41-
<NextLink href={`/library/agents/${id}`} className="w-full flex-shrink-0">
42-
<div className="flex items-center gap-2 px-4 pt-3">
39+
<NextLink href={`/library/agents/${id}`} className="flex-shrink-0">
40+
<div className="relative flex items-center gap-2 px-4 pt-3">
4341
<Avatar className="h-4 w-4 rounded-full">
4442
<AvatarImage
4543
src={
@@ -58,13 +56,13 @@ export function LibraryAgentCard({ agent }: Props) {
5856
{isFromMarketplace ? "FROM MARKETPLACE" : "Built by you"}
5957
</Text>
6058
</div>
61-
{isAgentFavoritingEnabled && (
62-
<FavoriteButton
63-
isFavorite={isFavorite}
64-
onClick={handleToggleFavorite}
65-
/>
66-
)}
6759
</NextLink>
60+
<FavoriteButton
61+
isFavorite={isFavorite}
62+
onClick={handleToggleFavorite}
63+
className="absolute right-10 top-0"
64+
/>
65+
<AgentCardMenu agent={agent} />
6866

6967
<div className="flex w-full flex-1 flex-col px-4 pb-2">
7068
<Link

autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/components/FavoriteButton.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,27 @@
22

33
import { cn } from "@/lib/utils";
44
import { HeartIcon } from "@phosphor-icons/react";
5+
import type { MouseEvent } from "react";
56

67
interface FavoriteButtonProps {
78
isFavorite: boolean;
8-
onClick: (e: React.MouseEvent) => void;
9+
onClick: (e: MouseEvent<HTMLButtonElement>) => void;
10+
className?: string;
911
}
1012

11-
export function FavoriteButton({ isFavorite, onClick }: FavoriteButtonProps) {
13+
export function FavoriteButton({
14+
isFavorite,
15+
onClick,
16+
className,
17+
}: FavoriteButtonProps) {
1218
return (
1319
<button
1420
onClick={onClick}
1521
className={cn(
16-
"rounded-full bg-white/90 p-2 backdrop-blur-sm transition-all duration-200",
17-
"hover:scale-110 hover:bg-white",
18-
"focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2",
22+
"rounded-full p-2 transition-all duration-200",
23+
"hover:scale-110",
1924
!isFavorite && "opacity-0 group-hover:opacity-100",
25+
className,
2026
)}
2127
aria-label={isFavorite ? "Remove from favorites" : "Add to favorites"}
2228
>

autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentCard/useLibraryAgentCard.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { useGetV2GetUserProfile } from "@/app/api/__generated__/endpoints/store/
88
import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent";
99
import { okData } from "@/app/api/helpers";
1010
import { useToast } from "@/components/molecules/Toast/use-toast";
11-
import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag";
1211
import { updateFavoriteInQueries } from "./helpers";
1312

1413
interface Props {
@@ -20,7 +19,6 @@ export function useLibraryAgentCard({ agent }: Props) {
2019
agent;
2120

2221
const isFromMarketplace = Boolean(marketplace_listing);
23-
const isAgentFavoritingEnabled = useGetFlag(Flag.AGENT_FAVORITING);
2422
const [isFavorite, setIsFavorite] = useState(is_favorite);
2523
const { toast } = useToast();
2624
const queryClient = getQueryClient();
@@ -49,8 +47,6 @@ export function useLibraryAgentCard({ agent }: Props) {
4947
e.preventDefault();
5048
e.stopPropagation();
5149

52-
if (!isAgentFavoritingEnabled) return;
53-
5450
const newIsFavorite = !isFavorite;
5551

5652
setIsFavorite(newIsFavorite);
@@ -80,7 +76,6 @@ export function useLibraryAgentCard({ agent }: Props) {
8076

8177
return {
8278
isFromMarketplace,
83-
isAgentFavoritingEnabled,
8479
isFavorite,
8580
profile,
8681
creator_image_url,

autogpt_platform/frontend/src/app/(platform)/library/hooks/useFavoriteAgents.ts

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
"use client";
22

3-
import {
4-
getPaginatedTotalCount,
5-
getPaginationNextPageNumber,
6-
unpaginate,
7-
} from "@/app/api/helpers";
83
import { useGetV2ListFavoriteLibraryAgentsInfinite } from "@/app/api/__generated__/endpoints/library/library";
4+
import { getPaginationNextPageNumber, unpaginate } from "@/app/api/helpers";
5+
import { useMemo } from "react";
6+
import { filterAgents } from "../components/LibraryAgentList/helpers";
97

10-
export function useFavoriteAgents() {
8+
interface Props {
9+
searchTerm: string;
10+
}
11+
12+
export function useFavoriteAgents({ searchTerm }: Props) {
1113
const {
1214
data: agentsQueryData,
1315
fetchNextPage,
@@ -27,10 +29,16 @@ export function useFavoriteAgents() {
2729
const allAgents = agentsQueryData
2830
? unpaginate(agentsQueryData, "agents")
2931
: [];
30-
const agentCount = getPaginatedTotalCount(agentsQueryData);
32+
33+
const filteredAgents = useMemo(
34+
() => filterAgents(allAgents, searchTerm),
35+
[allAgents, searchTerm],
36+
);
37+
38+
const agentCount = filteredAgents.length;
3139

3240
return {
33-
allAgents,
41+
allAgents: filteredAgents,
3442
agentLoading,
3543
hasNextPage,
3644
agentCount,

autogpt_platform/frontend/src/app/(platform)/library/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export default function LibraryPage() {
1717
return (
1818
<main className="pt-160 container min-h-screen space-y-4 pb-20 pt-16 sm:px-8 md:px-12">
1919
<LibraryActionHeader setSearchTerm={setSearchTerm} />
20-
<FavoritesSection />
20+
<FavoritesSection searchTerm={searchTerm} />
2121
<LibraryAgentList
2222
searchTerm={searchTerm}
2323
librarySort={librarySort}

autogpt_platform/frontend/src/components/molecules/Toast/styles.module.css

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,3 @@ html body .toastDescription {
3737
font-size: 0.75rem !important;
3838
line-height: 1.25rem !important;
3939
}
40-
41-
/* Position close button on the right */
42-
/* stylelint-disable-next-line selector-pseudo-class-no-unknown */
43-
#root [data-sonner-toast] [data-close-button="true"] {
44-
left: unset !important;
45-
right: -18px !important;
46-
top: -3px !important;
47-
}

autogpt_platform/frontend/src/components/molecules/Toast/toaster.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use client";
22

3-
import { CheckCircle, Info, Warning, XCircle } from "@phosphor-icons/react";
43
import { Toaster as SonnerToaster } from "sonner";
54
import styles from "./styles.module.css";
65

@@ -23,10 +22,10 @@ export function Toaster() {
2322
}}
2423
className="custom__toast"
2524
icons={{
26-
success: <CheckCircle className="h-4 w-4" color="#fff" weight="fill" />,
27-
error: <XCircle className="h-4 w-4" color="#fff" weight="fill" />,
28-
warning: <Warning className="h-4 w-4" color="#fff" weight="fill" />,
29-
info: <Info className="h-4 w-4" color="#fff" weight="fill" />,
25+
success: null,
26+
error: null,
27+
warning: null,
28+
info: null,
3029
}}
3130
/>
3231
);

0 commit comments

Comments
 (0)