diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx index 3e0dcfe525..fd5163d8e4 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/LibraryAgentList.tsx @@ -11,11 +11,72 @@ import { Button } from "@/components/atoms/Button/Button"; import { ArrowLeftIcon, HeartIcon } from "@phosphor-icons/react"; import { Text } from "@/components/atoms/Text/Text"; import { Tab } from "../LibraryTabs/LibraryTabs"; -import { LayoutGroup } from "framer-motion"; +import { + AnimatePresence, + LayoutGroup, + motion, + useReducedMotion, +} from "framer-motion"; import { LibraryFolderEditDialog } from "../LibraryFolderEditDialog/LibraryFolderEditDialog"; import { LibraryFolderDeleteDialog } from "../LibraryFolderDeleteDialog/LibraryFolderDeleteDialog"; import { useLibraryAgentList } from "./useLibraryAgentList"; +const containerVariants = { + hidden: {}, + show: { + transition: { + staggerChildren: 0.04, + delayChildren: 0.04, + }, + }, + exit: { + opacity: 0, + filter: "blur(4px)", + transition: { + duration: 0.15, + ease: [0.25, 0.1, 0.25, 1], + }, + }, +}; + +const itemVariants = { + hidden: { + opacity: 0, + y: 8, + scale: 0.96, + filter: "blur(4px)", + }, + show: { + opacity: 1, + y: 0, + scale: 1, + filter: "blur(0px)", + transition: { + duration: 0.25, + ease: [0.25, 0.1, 0.25, 1], + }, + }, +}; + +const reducedContainerVariants = { + hidden: {}, + show: { + transition: { staggerChildren: 0.02 }, + }, + exit: { + opacity: 0, + transition: { duration: 0.15 }, + }, +}; + +const reducedItemVariants = { + hidden: { opacity: 0 }, + show: { + opacity: 1, + transition: { duration: 0.2 }, + }, +}; + interface Props { searchTerm: string; librarySort: LibraryAgentSort; @@ -37,6 +98,14 @@ export function LibraryAgentList({ activeTab, onTabChange, }: Props) { + const shouldReduceMotion = useReducedMotion(); + const activeContainerVariants = shouldReduceMotion + ? reducedContainerVariants + : containerVariants; + const activeItemVariants = shouldReduceMotion + ? reducedItemVariants + : itemVariants; + const { isFavoritesTab, agentLoading, @@ -112,26 +181,38 @@ export function LibraryAgentList({ loader={} > -
- {showFolders && - foldersData?.folders.map((folder) => ( - onFolderSelect(folder.id)} - onEdit={() => setEditingFolder(folder)} - onDelete={() => setDeletingFolder(folder)} - /> + + + {showFolders && + foldersData?.folders.map((folder) => ( + + onFolderSelect(folder.id)} + onEdit={() => setEditingFolder(folder)} + onDelete={() => setDeletingFolder(folder)} + /> + + ))} + {agents.map((agent) => ( + + + ))} - {agents.map((agent) => ( - - ))} -
+ +
)} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx index 7af688f230..e1f9e2f734 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx @@ -57,7 +57,7 @@ export function LibraryFolder({
({ - queryKey: getGetV2ListLibraryFoldersQueryKey(), - }); + const previousData = + queryClient.getQueriesData({ + queryKey: getGetV2ListLibraryFoldersQueryKey(), + }); queryClient.setQueriesData( { queryKey: getGetV2ListLibraryFoldersQueryKey() }, @@ -123,8 +122,7 @@ export function LibraryFolderEditDialog({ folder, isOpen, setIsOpen }: Props) { queryClient.setQueryData(queryKey, data); } } - const detail = - error.detail ?? error.response?.detail ?? ""; + const detail = error.detail ?? error.response?.detail ?? ""; if ( typeof detail === "string" && detail.toLowerCase().includes("already exists") @@ -191,7 +189,7 @@ export function LibraryFolderEditDialog({ folder, isOpen, setIsOpen }: Props) {
onSubmit(values)} - className="flex flex-col justify-center gap-4 px-1" + className="flex flex-col justify-center gap-2 px-1" > @@ -224,6 +223,7 @@ export function LibraryFolderEditDialog({ folder, isOpen, setIsOpen }: Props) { placeholder="Select a color" value={field.value} onValueChange={field.onChange} + wrapperClassName="!mb-0" options={FOLDER_COLORS.map((color) => ({ value: color.value, label: color.label, @@ -273,10 +273,13 @@ export function LibraryFolderEditDialog({ folder, isOpen, setIsOpen }: Props) { field.onChange(emoji); }} emojiSize={32} - className="w-full" + className="w-full rounded-2xl px-2" > - - + +
diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryTabs/LibraryTabs.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryTabs/LibraryTabs.tsx index 59925ccd07..88fd29bc0f 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryTabs/LibraryTabs.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryTabs/LibraryTabs.tsx @@ -19,11 +19,16 @@ interface Props { layoutId?: string; } -export function LibraryTabs({ tabs, activeTab, onTabChange, layoutId = "library-tabs" }: Props) { +export function LibraryTabs({ + tabs, + activeTab, + onTabChange, + layoutId = "library-tabs", +}: Props) { const { registerFavoritesTabRef } = useFavoriteAnimation(); return ( -
+
{tabs.map((tab) => ( ))}
@@ -46,7 +53,13 @@ interface TabButtonProps { onRefReady?: (element: HTMLElement | null) => void; } -function TabButton({ tab, isActive, onSelect, layoutId, onRefReady }: TabButtonProps) { +function TabButton({ + tab, + isActive, + onSelect, + layoutId, + onRefReady, +}: TabButtonProps) { const [isLoaded, setIsLoaded] = useState(false); const buttonRef = useRef(null); @@ -82,7 +95,7 @@ function TabButton({ tab, isActive, onSelect, layoutId, onRefReady }: TabButtonP onSelect(tab.id); setIsLoaded(true); }} - className="w-fit h-fit flex" + className="flex h-fit w-fit" style={{ willChange: "transform" }} > {tab.title}