diff --git a/desktop/src/features/agents/ui/TeamsSection.tsx b/desktop/src/features/agents/ui/TeamsSection.tsx index 478c4fbc2..223b155dd 100644 --- a/desktop/src/features/agents/ui/TeamsSection.tsx +++ b/desktop/src/features/agents/ui/TeamsSection.tsx @@ -19,8 +19,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; -import { Card } from "@/shared/ui/card"; -import { Skeleton } from "@/shared/ui/skeleton"; +import { IdentityCardSkeleton } from "@/shared/ui/identity-card-skeleton"; import { CreateIdentityCard } from "./CreateIdentityCard"; import { TeamIdentityCard } from "./TeamIdentityCard"; @@ -102,20 +101,27 @@ export function TeamsSection({ {isLoading ? (
- {["first", "second", "third"].map((key) => ( - -
- - - - -
- - -
-
-
- ))} + + +
) : null} diff --git a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx index d05e0e297..698fa7c09 100644 --- a/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx +++ b/desktop/src/features/agents/ui/UnifiedAgentsSection.tsx @@ -14,7 +14,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; -import { Skeleton } from "@/shared/ui/skeleton"; +import { IdentityCardSkeleton } from "@/shared/ui/identity-card-skeleton"; import { AgentIdentityCard } from "./AgentIdentityCard"; import { CreateIdentityCard } from "./CreateIdentityCard"; @@ -408,19 +408,18 @@ function NewAgentCard({ function LoadingSkeleton() { return (
- {["a", "b", "c"].map((k) => ( -
-
- - -
- - -
- ))} + + +
); } diff --git a/desktop/src/shared/ui/ViewLoadingFallback.tsx b/desktop/src/shared/ui/ViewLoadingFallback.tsx index 09cef4904..ebb55e3ff 100644 --- a/desktop/src/shared/ui/ViewLoadingFallback.tsx +++ b/desktop/src/shared/ui/ViewLoadingFallback.tsx @@ -1,5 +1,6 @@ import { Card } from "@/shared/ui/card"; import { Skeleton } from "@/shared/ui/skeleton"; +import { IdentityCardSkeleton } from "@/shared/ui/identity-card-skeleton"; import { cn } from "@/shared/lib/cn"; import { channelChrome, topChromeInset } from "@/shared/layout/chromeLayout"; import { TopChromeInsetHeader } from "@/shared/layout/TopChromeInsetHeader"; @@ -69,119 +70,8 @@ function MessageRowsSkeleton() { ); } -const agentLoadingGroups = [ - { - badgeWidth: "w-14", - instanceWidth: "w-20", - key: "persona-one", - rows: ["one-a", "one-b"], - titleWidth: "w-32", - }, - { - badgeWidth: "w-16", - instanceWidth: "w-24", - key: "persona-two", - rows: ["two-a"], - titleWidth: "w-28", - }, - { - badgeWidth: "w-12", - instanceWidth: "w-20", - key: "custom-agents", - rows: ["custom-a"], - titleWidth: "w-36", - }, -] as const; - -function AgentRowSkeleton({ variant = 0 }: { variant?: number }) { - return ( -
-
-
-
-
- - -
-
- - -
-
- - -
- {variant === 0 ? ( -
- - -
- ) : null} -
-
-
- -
- - -
- -
- -
- - {variant === 0 ? : null} -
-
-
-
- -
- - -
-
- ); -} - -function AgentGroupSkeleton({ - badgeWidth, - instanceWidth, - rows, - titleWidth, -}: { - badgeWidth: string; - instanceWidth: string; - rows: readonly string[]; - titleWidth: string; -}) { - return ( -
-
-
- - -
- - -
- -
- -
- -
- {rows.map((row, index) => ( - - ))} -
-
- ); -} +const AGENTS_LOADING_GRID_CLASS = + "grid grid-cols-[repeat(auto-fill,minmax(220px,240px))] justify-start gap-3"; function AgentsLibrarySkeleton() { return ( @@ -189,24 +79,23 @@ function AgentsLibrarySkeleton() {
- -
-
- - +
-
- {agentLoadingGroups.map((group) => ( - - ))} +
+ + +
); @@ -218,41 +107,32 @@ function AgentTeamsSkeleton() {
- -
-
- - +
-
- {["team-one", "team-two", "team-three"].map((key, index) => ( - -
-
-
- - - {index === 1 ? ( - - ) : null} -
-
-
- - - -
- -
-
- -
-
- ))} +
+ + +
); diff --git a/desktop/src/shared/ui/identity-card-skeleton.tsx b/desktop/src/shared/ui/identity-card-skeleton.tsx new file mode 100644 index 000000000..31d967eec --- /dev/null +++ b/desktop/src/shared/ui/identity-card-skeleton.tsx @@ -0,0 +1,103 @@ +import { cn } from "@/shared/lib/cn"; +import { Skeleton } from "@/shared/ui/skeleton"; + +type IdentityCardSkeletonProps = { + className?: string; + footerSubtitleWidthClass?: string; + footerTitleWidthClass?: string; + kind?: "single" | "stack"; + showAction?: boolean; + stackCount?: number; +}; + +const MAX_STACK_ITEMS = 6; +const STACK_ITEM_KEYS = [ + "first", + "second", + "third", + "fourth", + "fifth", + "sixth", +]; + +export function IdentityCardSkeleton({ + className, + footerSubtitleWidthClass = "w-16", + footerTitleWidthClass = "w-28", + kind = "single", + showAction = false, + stackCount = 3, +}: IdentityCardSkeletonProps) { + return ( +
+ {showAction ? ( + + ) : null} + + {kind === "stack" ? ( + + ) : ( + + )} + +
+ + +
+
+ ); +} + +function SingleAvatarSkeleton() { + return ( +
+ +
+ ); +} + +function StackSkeleton({ count }: { count: number }) { + const visibleCount = Math.max(1, Math.min(count, MAX_STACK_ITEMS)); + const { overlap, size } = getStackMetrics(visibleCount); + + return ( +
+
+ {STACK_ITEM_KEYS.slice(0, visibleCount).map((key, index) => ( + 0 ? -overlap : 0, + width: size, + zIndex: index + 1, + }} + /> + ))} +
+
+ ); +} + +function getStackMetrics(count: number) { + switch (count) { + case 1: + return { overlap: 0, size: 152 }; + case 2: + return { overlap: 44, size: 124 }; + case 3: + return { overlap: 46, size: 108 }; + case 4: + return { overlap: 50, size: 96 }; + case 5: + return { overlap: 48, size: 86 }; + default: + return { overlap: 46, size: 78 }; + } +}