ppt-tool/frontend/components/ui/button.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

61 lines
2.2 KiB
TypeScript

import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition-all duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-[hsl(var(--primary))] text-primary-foreground shadow-md hover:shadow-lg hover:bg-[hsl(var(--primary-hover))] active:scale-95",
destructive:
"bg-[hsl(var(--error))] text-error-foreground shadow-md hover:shadow-lg hover:bg-[hsl(var(--error))]/90 active:scale-95",
outline:
"border-2 border-border bg-background hover:bg-[hsl(var(--surface))] hover:border-[hsl(var(--primary))] active:scale-95",
secondary:
"bg-[hsl(var(--surface))] text-foreground hover:bg-[hsl(var(--surface-hover))] shadow-sm active:scale-95",
ghost:
"hover:bg-[hsl(var(--surface))] active:scale-95",
link:
"text-[hsl(var(--primary))] underline-offset-4 hover:underline",
success:
"bg-[hsl(var(--success))] text-success-foreground shadow-md hover:shadow-lg hover:bg-[hsl(var(--success))]/90 active:scale-95",
},
size: {
default: "h-10 px-4 py-2 text-base",
sm: "h-9 px-3 text-sm",
lg: "h-12 px-6 text-lg",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }