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>
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
/**
|
|
* Hamster wheel loading animation.
|
|
* From Uiverse.io by Nawsome — converted to React component.
|
|
*/
|
|
import React from 'react';
|
|
|
|
interface HamsterLoaderProps {
|
|
size?: 'sm' | 'md' | 'lg';
|
|
className?: string;
|
|
}
|
|
|
|
const SIZE_MAP = {
|
|
sm: '8px',
|
|
md: '14px',
|
|
lg: '20px',
|
|
};
|
|
|
|
export function HamsterLoader({ size = 'md', className = '' }: HamsterLoaderProps) {
|
|
return (
|
|
<div
|
|
aria-label="Loading"
|
|
role="status"
|
|
className={`wheel-and-hamster ${className}`}
|
|
style={{ fontSize: SIZE_MAP[size] }}
|
|
>
|
|
<div className="wheel" />
|
|
<div className="hamster">
|
|
<div className="hamster__body">
|
|
<div className="hamster__head">
|
|
<div className="hamster__ear" />
|
|
<div className="hamster__eye" />
|
|
<div className="hamster__nose" />
|
|
</div>
|
|
<div className="hamster__limb hamster__limb--fr" />
|
|
<div className="hamster__limb hamster__limb--fl" />
|
|
<div className="hamster__limb hamster__limb--br" />
|
|
<div className="hamster__limb hamster__limb--bl" />
|
|
<div className="hamster__tail" />
|
|
</div>
|
|
</div>
|
|
<div className="spoke" />
|
|
</div>
|
|
);
|
|
}
|