ppt-tool/frontend/components/shared/Card.tsx
Vadym Samoilenko c431d4ab45 Implement critical security fixes and modern design system (Pre-launch P0 tasks)
Security Improvements (P0.0-P0.4):
- P0.0: Migrate to Gemini-only AI stack (simplified, single billing)
- P0.1: Fix CORS to restrict allowed origins from env (was *)
- P0.2: Remove hardcoded dev password, require env var
- P0.3: Add rate limiting (slowapi) - 3-10 req/min on sensitive endpoints
- P0.4: Add request size limits (100MB default via middleware)

New Features:
- Unified LLM service with Google Gemini priority
- OXML geometry extractor for layout parsing
- TSX validator for generated React components
- Client ID support in presentation requests with access control
- Configurable LLM/image timeouts via env vars

Modern Design System (P0.9 - partial):
- Enhanced CSS design tokens (primary, semantic colors, shadows)
- Typography scale (h1-h4, body variants, caption)
- Modern animations (fadeIn, slideIn, scaleIn)
- Updated Button component with better variants and hover effects
- Created unified Card and StatusBadge components
- Applied design system to Dashboard and Settings pages

Backend Improvements:
- Master deck parser simplification
- Slide-to-HTML endpoint cleanup (325 lines removed)
- Better error handling in prompts endpoint

Frontend Improvements:
- Settings UI simplified to show only Google/Gemini
- Dashboard uses CSS variables instead of hardcoded colors
- Improved button transitions and hover states

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-27 18:28:24 +00:00

69 lines
1.7 KiB
TypeScript

import { cn } from "@/lib/utils";
interface CardProps {
children: React.ReactNode;
hover?: boolean;
className?: string;
onClick?: () => void;
}
export function Card({ children, hover = false, className = "", onClick }: CardProps) {
return (
<div
className={cn(
"bg-white rounded-xl border border-border p-6",
"transition-all duration-200",
hover && "hover:shadow-lg hover:border-[hsl(var(--primary))]/20 cursor-pointer hover:-translate-y-1",
className
)}
onClick={onClick}
>
{children}
</div>
);
}
interface CardHeaderProps {
children: React.ReactNode;
className?: string;
}
export function CardHeader({ children, className = "" }: CardHeaderProps) {
return <div className={cn("mb-4", className)}>{children}</div>;
}
interface CardTitleProps {
children: React.ReactNode;
className?: string;
}
export function CardTitle({ children, className = "" }: CardTitleProps) {
return <h3 className={cn("text-xl font-semibold", className)}>{children}</h3>;
}
interface CardDescriptionProps {
children: React.ReactNode;
className?: string;
}
export function CardDescription({ children, className = "" }: CardDescriptionProps) {
return <p className={cn("text-sm text-muted-foreground", className)}>{children}</p>;
}
interface CardContentProps {
children: React.ReactNode;
className?: string;
}
export function CardContent({ children, className = "" }: CardContentProps) {
return <div className={cn(className)}>{children}</div>;
}
interface CardFooterProps {
children: React.ReactNode;
className?: string;
}
export function CardFooter({ children, className = "" }: CardFooterProps) {
return <div className={cn("mt-4 pt-4 border-t border-border", className)}>{children}</div>;
}