From e02687ad09756a7f8291d9c05a7bf6b76d4b9cf3 Mon Sep 17 00:00:00 2001 From: abhi1992002 Date: Fri, 23 Jan 2026 15:41:01 +0530 Subject: [PATCH] library folder basic UI --- .../LibraryAgentList/LibraryAgentList.tsx | 6 + .../components/LibraryFolder/FolderIcon.tsx | 197 ++++++++++++++++++ .../LibraryFolder/LibraryFolder.tsx | 116 +++++++++++ 3 files changed, 319 insertions(+) create mode 100644 autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx create mode 100644 autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx 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 074cd8ae26..d1fa365e87 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 @@ -5,6 +5,7 @@ import { InfiniteScroll } from "@/components/contextual/InfiniteScroll/InfiniteS import { LibraryActionSubHeader } from "../LibraryActionSubHeader/LibraryActionSubHeader"; import { LibraryAgentCard } from "../LibraryAgentCard/LibraryAgentCard"; import { useLibraryAgentList } from "./useLibraryAgentList"; +import { LibraryFolder } from "../LibraryFolder/LibraryFolder"; interface Props { searchTerm: string; @@ -45,6 +46,11 @@ export function LibraryAgentList({ loader={} >
+ + + + + {agents.map((agent) => ( ))} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx new file mode 100644 index 0000000000..3a0dbab363 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/FolderIcon.tsx @@ -0,0 +1,197 @@ +import { useState } from "react"; +import { motion } from "framer-motion"; +import { Text } from "@/components/atoms/Text/Text"; + +type FolderSize = "xs" | "sm" | "md" | "lg" | "xl"; +export type FolderColor = + | "neutral" + | "slate" + | "zinc" + | "stone" + | "red" + | "orange" + | "amber" + | "yellow" + | "lime" + | "green" + | "emerald" + | "teal" + | "cyan" + | "sky" + | "blue" + | "indigo" + | "violet" + | "purple" + | "fuchsia" + | "pink" + | "rose"; + +interface Props { + className?: string; + size?: FolderSize | number; + color?: FolderColor; + icon?: string; + isOpen?: boolean; +} + +const sizeMap: Record = { + xs: 0.5, + sm: 0.75, + md: 1, + lg: 1.25, + xl: 1.5, +}; + +const colorMap: Record< + FolderColor, + { bg: string; border: string; borderLight: string; fill: string; stroke: string } +> = { + neutral: { bg: "bg-neutral-300", border: "border-neutral-300", borderLight: "border-neutral-200", fill: "fill-neutral-300", stroke: "stroke-neutral-400" }, + slate: { bg: "bg-slate-300", border: "border-slate-300", borderLight: "border-slate-200", fill: "fill-slate-300", stroke: "stroke-slate-400" }, + zinc: { bg: "bg-zinc-300", border: "border-zinc-300", borderLight: "border-zinc-200", fill: "fill-zinc-300", stroke: "stroke-zinc-400" }, + stone: { bg: "bg-stone-300", border: "border-stone-300", borderLight: "border-stone-200", fill: "fill-stone-300", stroke: "stroke-stone-400" }, + red: { bg: "bg-red-300", border: "border-red-300", borderLight: "border-red-200", fill: "fill-red-300", stroke: "stroke-red-400" }, + orange: { bg: "bg-orange-200", border: "border-orange-200", borderLight: "border-orange-200", fill: "fill-orange-200", stroke: "stroke-orange-400" }, + amber: { bg: "bg-amber-200", border: "border-amber-200", borderLight: "border-amber-200", fill: "fill-amber-200", stroke: "stroke-amber-400" }, + yellow: { bg: "bg-yellow-200", border: "border-yellow-200", borderLight: "border-yellow-200", fill: "fill-yellow-200", stroke: "stroke-yellow-400" }, + lime: { bg: "bg-lime-300", border: "border-lime-300", borderLight: "border-lime-200", fill: "fill-lime-300", stroke: "stroke-lime-400" }, + green: { bg: "bg-green-200", border: "border-green-200", borderLight: "border-green-200", fill: "fill-green-200", stroke: "stroke-green-400" }, + emerald: { bg: "bg-emerald-300", border: "border-emerald-300", borderLight: "border-emerald-200", fill: "fill-emerald-300", stroke: "stroke-emerald-400" }, + teal: { bg: "bg-teal-300", border: "border-teal-300", borderLight: "border-teal-200", fill: "fill-teal-300", stroke: "stroke-teal-400" }, + cyan: { bg: "bg-cyan-300", border: "border-cyan-300", borderLight: "border-cyan-200", fill: "fill-cyan-300", stroke: "stroke-cyan-400" }, + sky: { bg: "bg-sky-300", border: "border-sky-300", borderLight: "border-sky-200", fill: "fill-sky-300", stroke: "stroke-sky-400" }, + blue: { bg: "bg-blue-300", border: "border-blue-300", borderLight: "border-blue-200", fill: "fill-blue-300", stroke: "stroke-blue-400" }, + indigo: { bg: "bg-indigo-300", border: "border-indigo-300", borderLight: "border-indigo-200", fill: "fill-indigo-300", stroke: "stroke-indigo-400" }, + violet: { bg: "bg-violet-300", border: "border-violet-300", borderLight: "border-violet-200", fill: "fill-violet-300", stroke: "stroke-violet-400" }, + purple: { bg: "bg-purple-200", border: "border-purple-200", borderLight: "border-purple-200", fill: "fill-purple-200", stroke: "stroke-purple-400" }, + fuchsia: { bg: "bg-fuchsia-300", border: "border-fuchsia-300", borderLight: "border-fuchsia-200", fill: "fill-fuchsia-300", stroke: "stroke-fuchsia-400" }, + pink: { bg: "bg-pink-300", border: "border-pink-300", borderLight: "border-pink-200", fill: "fill-pink-300", stroke: "stroke-pink-400" }, + rose: { bg: "bg-rose-300", border: "border-rose-300", borderLight: "border-rose-200", fill: "fill-rose-300", stroke: "stroke-rose-400" }, +}; + +export function FolderIcon({ + className = "", + size = "xs", + color = "blue", + icon, + isOpen = false, +}: Props) { + const scale = typeof size === "number" ? size : sizeMap[size]; + const colors = colorMap[color]; + + return ( +
+
+
+ {[ + { + initial: { rotate: -3, x: -38, y: 2 }, + open: { rotate: -8, x: -70, y: -75 }, + transition: { + type: "spring" as const, + bounce: 0.15, + stiffness: 160, + damping: 22, + }, + className: "z-10", + }, + { + initial: { rotate: 0, x: 0, y: 0 }, + open: { rotate: 1, x: 2, y: -95 }, + transition: { + type: "spring" as const, + duration: 0.55, + bounce: 0.12, + stiffness: 190, + damping: 24, + }, + className: "z-20", + }, + { + initial: { rotate: 3.5, x: 42, y: 1 }, + open: { rotate: 9, x: 75, y: -80 }, + transition: { + type: "spring" as const, + duration: 0.58, + bounce: 0.17, + stiffness: 170, + damping: 21, + }, + className: "z-10", + }, + ].map((page, i) => ( + + + + ))} +
+ + + + + + +
+ {icon} +
+
+
+
+ ); +} + +interface PageProps { + color: FolderColor; +} + +function Page({ color = "blue" }: PageProps) { + const colors = colorMap[color]; + return ( +
+
+ agent.json + {Array.from({ length: 8 }).map((_, i) => ( +
+
+
+
+ ))} +
+
+ ); +} 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 new file mode 100644 index 0000000000..f321c0bd98 --- /dev/null +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryFolder/LibraryFolder.tsx @@ -0,0 +1,116 @@ +"use client"; + +import { Text } from "@/components/atoms/Text/Text"; +import { Button } from "@/components/atoms/Button/Button"; +import { FolderIcon, FolderColor } from "./FolderIcon"; +import { useState } from "react"; +import { + PencilSimpleIcon, + TrashIcon, + StarIcon, +} from "@phosphor-icons/react"; + +interface Props { + name: string; + agentCount: number; + color: FolderColor; + icon: string; + onEdit?: () => void; + onDelete?: () => void; + onFavorite?: () => void; + isFavorite?: boolean; +} + +export function LibraryFolder({ + name, + agentCount, + color, + icon, + onEdit, + onDelete, + onFavorite, + isFavorite = false, +}: Props) { + const [isHovered, setIsHovered] = useState(false); + + return ( +
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > +
+ {/* Left side - Folder name and agent count */} +
+ + {name} + + + {agentCount} {agentCount === 1 ? "agent" : "agents"} + +
+ + {/* Right side - Custom folder icon */} +
+ +
+
+ + {/* Action buttons - visible on hover */} +
+ + + +
+
+ ); +}