biohazard-vfx-website/.cursor/rules/component-patterns.mdc
2025-10-23 05:11:03 -06:00

159 lines
3.7 KiB
Plaintext

---
globs: src/components/**/*.tsx
---
# Component Patterns
## Component Structure
### File Organization
- Place reusable components in `src/components/`
- Use PascalCase for component files: `ComponentName.tsx`
- Group related components in subdirectories when needed
### Component Template
```typescript
import { cn } from '@/lib/utils'
interface ComponentProps {
className?: string
children?: React.ReactNode
// Other props
}
export function ComponentName({
className,
children,
...props
}: ComponentProps) {
return (
<div className={cn("base-styles", className)} {...props}>
{children}
</div>
)
}
```
## shadcn/ui Integration
### Using shadcn/ui Components
```typescript
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
export function ProjectCard({ project }: { project: Project }) {
return (
<Card className="bg-black border-gray-800">
<CardHeader>
<CardTitle className="text-white">{project.title}</CardTitle>
</CardHeader>
<CardContent>
<Badge variant="outline">{project.category}</Badge>
</CardContent>
</Card>
)
}
```
### Extending shadcn/ui Components
```typescript
// Create wrapper components for common patterns
import { Button } from '@/components/ui/button'
import { cn } from '@/lib/utils'
interface PrimaryButtonProps extends React.ComponentProps<typeof Button> {
loading?: boolean
}
export function PrimaryButton({
loading,
className,
children,
...props
}: PrimaryButtonProps) {
return (
<Button
className={cn("bg-primary hover:bg-primary/90", className)}
disabled={loading}
{...props}
>
{loading ? "Loading..." : children}
</Button>
)
}
```
## Animation Patterns
### Framer Motion Usage
```typescript
import { motion } from 'framer-motion'
export function AnimatedCard({ children }: { children: React.ReactNode }) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="card-styles"
>
{children}
</motion.div>
)
}
```
## Component Composition
### Compound Components
```typescript
// Parent component
export function Accordion({ children }: { children: React.ReactNode }) {
return <div className="accordion-container">{children}</div>
}
// Child components
export function AccordionItem({ children }: { children: React.ReactNode }) {
return <div className="accordion-item">{children}</div>
}
export function AccordionTrigger({ children }: { children: React.ReactNode }) {
return <button className="accordion-trigger">{children}</button>
}
// Usage
<Accordion>
<AccordionItem>
<AccordionTrigger>Title</AccordionTrigger>
<AccordionContent>Content</AccordionContent>
</AccordionItem>
</Accordion>
```
## Props and TypeScript
### Interface Patterns
```typescript
// Use descriptive interface names
interface ProjectCardProps {
project: Project
variant?: 'default' | 'featured'
showDescription?: boolean
onSelect?: (project: Project) => void
}
// Use React.ComponentProps for extending HTML elements
interface CustomButtonProps extends React.ComponentProps<'button'> {
variant?: 'primary' | 'secondary'
size?: 'sm' | 'md' | 'lg'
}
```
## Styling Guidelines
1. **Tailwind First**: Use utility classes before custom CSS
2. **Conditional Classes**: Use `cn()` utility for conditional styling
3. **Responsive Design**: Mobile-first approach with responsive utilities
4. **Dark Theme**: Ensure all components work in dark mode
5. **Accessibility**: Include proper ARIA labels and semantic HTML