diff --git a/public/Agent/add.svg b/public/Agent/add.svg new file mode 100644 index 0000000..ea7ce2a --- /dev/null +++ b/public/Agent/add.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Agent/agent.svg b/public/Agent/agent.svg new file mode 100644 index 0000000..198e285 --- /dev/null +++ b/public/Agent/agent.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/public/Agent/redirect.svg b/public/Agent/redirect.svg new file mode 100644 index 0000000..00da6cf --- /dev/null +++ b/public/Agent/redirect.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/Dashboard/Card1.svg b/public/Dashboard/Card1.svg new file mode 100644 index 0000000..b001ec5 --- /dev/null +++ b/public/Dashboard/Card1.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/Dashboard/Card2.svg b/public/Dashboard/Card2.svg new file mode 100644 index 0000000..2bc2eb8 --- /dev/null +++ b/public/Dashboard/Card2.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/Dashboard/Card3.svg b/public/Dashboard/Card3.svg new file mode 100644 index 0000000..c32083f --- /dev/null +++ b/public/Dashboard/Card3.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/Dashboard/Card4.svg b/public/Dashboard/Card4.svg new file mode 100644 index 0000000..c32083f --- /dev/null +++ b/public/Dashboard/Card4.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/components/dashboard/agent-card.tsx b/src/components/dashboard/agent-card.tsx index 43e3359..30b7e82 100644 --- a/src/components/dashboard/agent-card.tsx +++ b/src/components/dashboard/agent-card.tsx @@ -27,22 +27,26 @@ export function AgentCard({ title, tags, description }: AgentCardProps) { ]; return ( -
-

{title}

+
+

+ {title} +

-
+
{tags.map((tag, index) => ( 2 */ - className={`${tagColors[index] || tagColors[0]} px-3 py-1 text-xs font-medium text-gray-700 border border-gray-200`} + className={`${tagColors[index] || tagColors[0]} px-2.5 py-1 md:px-3 text-[0.75rem] md:text-[0.8125rem] lg:text-[0.875rem] font-medium text-gray-700 border border-gray-200 rounded`} > {tag} ))}
-

{description}

+

+ {description} +

); } diff --git a/src/components/dashboard/agents-section.tsx b/src/components/dashboard/agents-section.tsx new file mode 100644 index 0000000..e59fa2d --- /dev/null +++ b/src/components/dashboard/agents-section.tsx @@ -0,0 +1,117 @@ +/** + * Agents Section Component + * @description Displays agents list with tabs and pagination + */ + +import { useState, useMemo, useEffect } from 'react'; +import { AgentCard } from './agent-card'; +import { Pagination } from './pagination'; +import type { AgentData } from '@/constants/agents'; + +/** + * Agents section component props + */ +interface AgentsSectionProps { + /** + * List of agents to display + */ + agents: AgentData[]; + /** + * Number of items per page + */ + itemsPerPage?: number; +} + +/** + * Agents section component + * @description Displays agents with tabs and pagination + * @param props - Component props + * @returns AgentsSection element + */ +export function AgentsSection({ agents, itemsPerPage = 6 }: AgentsSectionProps) { + const [activeTab, setActiveTab] = useState<'all' | 'my'>('all'); + const [currentPage, setCurrentPage] = useState(1); + + /** + * Calculate pagination values + */ + const paginationData = useMemo(() => { + const totalItems = agents.length; + const totalPages = Math.ceil(totalItems / itemsPerPage); + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = startIndex + itemsPerPage; + const paginatedAgents = agents.slice(startIndex, endIndex); + + return { + totalPages, + paginatedAgents, + }; + }, [agents, currentPage, itemsPerPage]); + + /** + * Reset pagination when tab changes + */ + useEffect(() => { + setCurrentPage(1); + }, [activeTab]); + + /** + * Handle page change + * @param page - New page number (1-indexed) + */ + const handlePageChange = (page: number) => { + setCurrentPage(page); + }; + + return ( +
+ {/* Tabs */} +
+ + +
+ + {/* Agent Cards Grid */} +
+ {paginationData.paginatedAgents.map((agent, index) => ( + + ))} +
+ + {/* Fixed Pagination at Bottom */} + {paginationData.totalPages > 1 && ( +
+ +
+ )} +
+ ); +} + diff --git a/src/components/dashboard/index.ts b/src/components/dashboard/index.ts index 9fe6a15..6868bb6 100644 --- a/src/components/dashboard/index.ts +++ b/src/components/dashboard/index.ts @@ -6,3 +6,5 @@ export { Sidebar } from './sidebar'; export { MetricCard } from './metric-card'; export { AgentCard } from './agent-card'; +export { Pagination } from './pagination'; +export { AgentsSection } from './agents-section'; diff --git a/src/components/dashboard/metric-card.tsx b/src/components/dashboard/metric-card.tsx index d41fef9..0faa656 100644 --- a/src/components/dashboard/metric-card.tsx +++ b/src/components/dashboard/metric-card.tsx @@ -1,72 +1,69 @@ -/** - * Metric Card Component - * @description Displays metric information with gradient background - */ - -/** - * MetricCard component props - */ interface MetricCardProps { title: string; subtitle: string; value: string; gradient: 'blue-teal' | 'pink-purple' | 'orange-yellow' | 'blue-purple'; + imageUrl?: string; } -/** - * MetricCard component - * @description Card showing metric with gradient background and premium styling - * @param props - Component props - * @returns MetricCard element - */ -export function MetricCard({ title, subtitle, value, gradient }: MetricCardProps) { - const gradients = { - 'blue-teal': ' bg-gradient-to-br from-[#001B2F] via-[#0626A8] to-[#039A98] text-white ', - 'pink-purple': 'bg-gradient-to-br from-[#FF6B8B] via-[#944D8F] to-[#51459E]', - 'orange-yellow': 'bg-gradient-to-br from-[#FF9D42] to-[#F17E31]', - 'blue-purple': 'bg-gradient-to-br from-[#2D5BFF] to-[#8E34FF]', +type GradientStyle = { + backgroundImage?: string; + background?: string; +}; + +export function MetricCard({ title, subtitle, value, gradient, imageUrl }: MetricCardProps) { + const gradientStyles: Record = { + 'blue-teal': { + backgroundImage: 'linear-gradient(16.03674192372833deg, rgba(0, 27, 47, 1) 10.549%, rgba(6, 38, 168, 1) 30.146%, rgba(3, 154, 152, 1) 77.418%)', + }, + 'pink-purple': { + background: 'linear-gradient(180deg, #ff708c 0%, #001377 100%)', + }, + 'orange-yellow': { + background: 'linear-gradient(180deg, #f3696e 0%, #f8a902 100%)', + }, + 'blue-purple': { + background: 'linear-gradient(180deg, #c336ff 0%, #0033ff 100%)', + }, }; - // return ( - //
- // {/* Right side decorative vertical bar */} - //
- - //
- //
- //

- // {title} - //

- //

- // {subtitle} - //

- //
- - //
- // - // {value} - // - //
- //
- //
- // ); + const imageUrls: Record = { + 'blue-teal': imageUrl || 'https://www.figma.com/api/mcp/asset/57e6c8be-018b-41d3-a71d-d59c115b529c', + 'pink-purple': imageUrl || 'https://www.figma.com/api/mcp/asset/ccb9eb9b-4d2e-417d-b727-8dcd1586344a', + 'orange-yellow': imageUrl || 'https://www.figma.com/api/mcp/asset/63c3ed6f-400a-431e-b3a7-43b6ff3d4eee', + 'blue-purple': imageUrl || 'https://www.figma.com/api/mcp/asset/e5d86ccf-d5ce-4b5e-823a-a01acb631af7', + }; + return ( -
-
-
- - {title} - - - {subtitle} - +
+
+ {/* Text Content Container */} +
+
+

+ {title} +

+

+ {subtitle} +

+
+

+ {value} +

-
- {value} + + {/* Image Container - Fixed to the right */} +
+
); -} - - +} \ No newline at end of file diff --git a/src/components/dashboard/pagination.tsx b/src/components/dashboard/pagination.tsx new file mode 100644 index 0000000..f2ef982 --- /dev/null +++ b/src/components/dashboard/pagination.tsx @@ -0,0 +1,163 @@ + +import { ChevronLeft, ChevronRight } from 'lucide-react'; + +interface PaginationProps { + currentPage: number; + totalPages: number; + onPageChange: (page: number) => void; +} + +/** + * Pagination component + * @description Displays pagination controls with page numbers and navigation arrows + * @param props - Component props + * @returns Pagination element + */ +export function Pagination({ currentPage, totalPages, onPageChange }: PaginationProps) { + /** + * Generate page numbers to display + * @returns Array of page numbers and ellipsis markers + */ + const getPageNumbers = (): (number | 'ellipsis')[] => { + const pages: (number | 'ellipsis')[] = []; + const maxVisible = 8; + + if (totalPages <= maxVisible) { + // Show all pages if total is less than max visible + for (let i = 1; i <= totalPages; i++) { + pages.push(i); + } + } else { + // Always show first page + pages.push(1); + + if (currentPage <= 3) { + // Near the beginning: show 1, 2, 3, ..., last + pages.push(2, 3); + if (totalPages > 4) { + pages.push('ellipsis'); + } + pages.push(totalPages); + } else if (currentPage >= totalPages - 2) { + // Near the end: show 1, ..., last-2, last-1, last + pages.push('ellipsis'); + pages.push(totalPages - 2, totalPages - 1, totalPages); + } else { + // In the middle: show 1, ..., current-1, current, current+1, ..., last + pages.push('ellipsis'); + pages.push(currentPage - 1, currentPage, currentPage + 1); + if (currentPage + 1 < totalPages - 1) { + pages.push('ellipsis'); + } + pages.push(totalPages); + } + } + + return pages; + }; + + /** + * Handle previous page navigation + */ + const handlePrevious = () => { + if (currentPage > 1) { + onPageChange(currentPage - 1); + } + }; + + /** + * Handle next page navigation + */ + const handleNext = () => { + if (currentPage < totalPages) { + onPageChange(currentPage + 1); + } + }; + + /** + * Handle page number click + * @param page - Page number to navigate to + */ + const handlePageClick = (page: number) => { + if (page !== currentPage && page >= 1 && page <= totalPages) { + onPageChange(page); + } + }; + + const pageNumbers = getPageNumbers(); + const isFirstPage = currentPage === 1; + const isLastPage = currentPage === totalPages; + + return ( +
+ {/* Previous Button */} + + + {/* Page Numbers */} + {pageNumbers.map((page, index) => { + if (page === 'ellipsis') { + return ( +
+ + ... + +
+ ); + } + + const isActive = page === currentPage; + + return ( + + ); + })} + + {/* Next Button */} + +
+ ); +} + diff --git a/src/components/dashboard/sidebar.tsx b/src/components/dashboard/sidebar.tsx index 0c61083..342ee07 100644 --- a/src/components/dashboard/sidebar.tsx +++ b/src/components/dashboard/sidebar.tsx @@ -1,9 +1,6 @@ -/** - * Dashboard Sidebar Component - * @description Vertical navigation sidebar with icons - */ - import { Home, Settings } from 'lucide-react'; +import { Link } from '@tanstack/react-router'; +import { APP_PATHS } from '@/routes'; /** * Sidebar component @@ -12,47 +9,57 @@ import { Home, Settings } from 'lucide-react'; */ export function Sidebar() { return ( -