Add frontend components for project/package/tag hierarchy views

- 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)
This commit is contained in:
Mondo Diaz
2025-12-12 10:10:10 -06:00
parent a4b4d700c2
commit 30774e429b
25 changed files with 2123 additions and 170 deletions

View File

@@ -0,0 +1,59 @@
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>;
}