diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..db2834a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,189 @@ +# AGENTS.md - Coding Guidelines for RagusaIT Web + +## Build Commands + +```bash +# Development server (port 3000) +npm run dev + +# Production build +npm run build + +# Preview production build +npm run preview +``` + +## Test Commands + +```bash +# Run all tests +npx vitest + +# Run tests in watch mode +npx vitest --watch + +# Run tests with coverage +npx vitest --coverage + +# Run a single test file +npx vitest src/components/ui/__tests__/Button.test.tsx + +# Run tests matching a pattern +npx vitest --grep "Button" + +# Run specific test by name +npx vitest -t "passes aria-label to the button element" +``` + +## Code Style Guidelines + +### TypeScript + +- Use **strict TypeScript** configuration +- Always define explicit return types for functions +- Use `type` for type definitions, `interface` for object shapes that may be extended +- Avoid `any` - use `unknown` when type is uncertain + +### Imports (Order) + +1. React imports +2. Third-party libraries (alphabetical) +3. Absolute imports from project (`@/components`, `@/utils`) +4. Relative imports +5. CSS/SCSS imports last + +```typescript +import { useState, useEffect } from 'react'; +import { motion } from 'motion/react'; +import { Link } from 'react-router-dom'; +import { useTranslation } from '../../i18n'; +import { debounce } from '../../utils/debounce'; +import styles from './Navbar.module.css'; +``` + +### Component Structure + +- Use **named exports** for all components +- Props interface should be named `[ComponentName]Props` +- Place props interface immediately before component +- Use CSS Modules for styling (`.module.css`) +- Destructure props in function signature with defaults + +```typescript +interface ButtonProps extends ButtonHTMLAttributes { + variant?: 'primary' | 'secondary' | 'outline'; + size?: 'sm' | 'md' | 'lg'; + isLoading?: boolean; +} + +export function Button({ + variant = 'primary', + size = 'md', + isLoading = false, + children, + ...props +}: ButtonProps) { + // Implementation +} +``` + +### Naming Conventions + +- **Components**: PascalCase (e.g., `Navbar`, `Button`) +- **Hooks**: camelCase with `use` prefix (e.g., `useRateLimit`, `useTypingEffect`) +- **Utilities**: camelCase (e.g., `debounce`, `formatDate`) +- **Types/Interfaces**: PascalCase (e.g., `ButtonProps`, `Translations`) +- **Constants**: UPPER_SNAKE_CASE for module-level constants +- **Files**: Match default export name (e.g., `Navbar.tsx` exports `Navbar`) + +### Error Handling + +- Use try-catch for async operations +- Provide meaningful error messages +- Use early returns to avoid nested conditionals +- Clean up resources (timers, event listeners) in useEffect cleanup + +```typescript +useEffect(() => { + const handleScroll = () => { + if (!ticking) { + window.requestAnimationFrame(() => { + setIsScrolled(window.scrollY > 20); + ticking = false; + }); + ticking = true; + } + }; + window.addEventListener('scroll', handleScroll, { passive: true }); + return () => window.removeEventListener('scroll', handleScroll); +}, []); +``` + +### Testing + +- Add `// @vitest-environment jsdom` at top of test files +- Use `describe` and `it` blocks with descriptive names +- Clean up after each test with `cleanup()` from testing-library +- Mock external dependencies appropriately +- Test behavior, not implementation + +```typescript +// @vitest-environment jsdom +import { render, screen, cleanup } from '@testing-library/react'; +import { describe, it, expect, afterEach } from 'vitest'; + +describe('Button', () => { + afterEach(() => { + cleanup(); + }); + + it('renders with correct aria-label', () => { + render(); + expect(screen.getByRole('button', { name: /submit/i })).toBeTruthy(); + }); +}); +``` + +### Performance + +- Use `React.lazy()` for code splitting on routes +- Memoize expensive calculations with `useMemo` +- Use `requestAnimationFrame` for scroll/resize handlers +- Debounce expensive operations (use `debounce` utility) +- Add `will-change` CSS sparingly for GPU acceleration + +### Accessibility + +- Always include meaningful `aria-label` for interactive elements +- Use semantic HTML elements (`
`, `