- Create reusable UI components: Badge, Breadcrumb, Card, DataTable, FilterChip, Pagination, SearchInput, SortDropdown - Update Home page with search, sort, filter, and pagination - Update ProjectPage with package stats, format filtering, keyboard nav - Update PackagePage with DataTable for tags, copy artifact ID, metadata - Add TypeScript types for paginated responses and list params - Update API client with pagination and filter query param support - URL-based state persistence for all filter/sort/page params - Keyboard navigation (Backspace to go up hierarchy)
60 lines
1.4 KiB
TypeScript
60 lines
1.4 KiB
TypeScript
import { ReactNode } from 'react';
|
|
import './Card.css';
|
|
|
|
interface CardProps {
|
|
children: ReactNode;
|
|
className?: string;
|
|
onClick?: () => void;
|
|
href?: string;
|
|
variant?: 'default' | 'elevated' | 'accent';
|
|
}
|
|
|
|
export function Card({ children, className = '', onClick, href, variant = 'default' }: CardProps) {
|
|
const baseClass = `card card--${variant} ${className}`.trim();
|
|
|
|
if (href) {
|
|
return (
|
|
<a href={href} className={`${baseClass} card--clickable`}>
|
|
{children}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
if (onClick) {
|
|
return (
|
|
<div className={`${baseClass} card--clickable`} onClick={onClick} role="button" tabIndex={0}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return <div className={baseClass}>{children}</div>;
|
|
}
|
|
|
|
interface CardHeaderProps {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function CardHeader({ children, className = '' }: CardHeaderProps) {
|
|
return <div className={`card__header ${className}`.trim()}>{children}</div>;
|
|
}
|
|
|
|
interface CardBodyProps {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function CardBody({ children, className = '' }: CardBodyProps) {
|
|
return <div className={`card__body ${className}`.trim()}>{children}</div>;
|
|
}
|
|
|
|
interface CardFooterProps {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
export function CardFooter({ children, className = '' }: CardFooterProps) {
|
|
return <div className={`card__footer ${className}`.trim()}>{children}</div>;
|
|
}
|