169 lines
4.5 KiB
Markdown
169 lines
4.5 KiB
Markdown
# AGENTS.md - Coding Guidelines for RagusaIT Web
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pnpm install
|
|
|
|
# Development server (port 3000)
|
|
pnpm dev
|
|
|
|
# Production build
|
|
pnpm build
|
|
|
|
# Preview production build
|
|
pnpm preview
|
|
```
|
|
|
|
## Test Commands
|
|
|
|
Use `pnpm exec` to run local binaries.
|
|
|
|
```bash
|
|
# Run all tests
|
|
pnpm exec vitest
|
|
|
|
# Run tests in watch mode
|
|
pnpm exec vitest --watch
|
|
|
|
# Run tests with coverage
|
|
pnpm exec vitest --coverage
|
|
|
|
# Run a single test file (Preferred method)
|
|
pnpm exec vitest src/components/ui/__tests__/Button.test.tsx
|
|
|
|
# Run tests matching a pattern
|
|
pnpm exec vitest --grep "Button"
|
|
|
|
# Run specific test by name
|
|
pnpm exec vitest -t "passes aria-label to the button element"
|
|
```
|
|
|
|
## Lint & Type Check
|
|
|
|
```bash
|
|
# Type check (strict)
|
|
pnpm exec tsc --noEmit
|
|
```
|
|
|
|
## Code Style Guidelines
|
|
|
|
### TypeScript
|
|
|
|
- Use **strict TypeScript** configuration (`strict: true`).
|
|
- 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.
|
|
- Use `import type` for type-only imports when possible.
|
|
|
|
### Imports (Order)
|
|
|
|
1. React imports (`react`, `react-dom`)
|
|
2. Third-party libraries (alphabetical, e.g., `motion/react`, `react-icons`)
|
|
3. Absolute imports from project (`@/components`, `@/utils` if configured, otherwise relative)
|
|
4. Relative imports (`../../utils`)
|
|
5. CSS/SCSS imports last (`./Component.module.css`)
|
|
|
|
```typescript
|
|
import { type ReactNode, type ButtonHTMLAttributes } from 'react';
|
|
import { motion } from 'motion/react';
|
|
import { Link } from 'react-router-dom';
|
|
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`).
|
|
- Use `motion` components (e.g., `motion.button`) for animations.
|
|
|
|
```typescript
|
|
interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onDrag'> {
|
|
variant?: 'primary' | 'secondary' | 'outline';
|
|
isLoading?: boolean;
|
|
}
|
|
|
|
export function Button({
|
|
variant = 'primary',
|
|
isLoading = false,
|
|
children,
|
|
className,
|
|
...props
|
|
}: ButtonProps) {
|
|
return (
|
|
<motion.button
|
|
className={`${styles.button} ${styles[variant]} ${className || ''}`}
|
|
whileTap={{ scale: 0.98 }}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</motion.button>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Naming Conventions
|
|
|
|
- **Components**: PascalCase (e.g., `Navbar`, `Button`)
|
|
- **Hooks**: camelCase with `use` prefix (e.g., `useRateLimit`)
|
|
- **Utilities**: camelCase (e.g., `debounce`, `formatDate`)
|
|
- **Types/Interfaces**: PascalCase (e.g., `ButtonProps`)
|
|
- **Files**: Match default export name (e.g., `Navbar.tsx` exports `Navbar`)
|
|
- **Test Files**: `[Filename].test.tsx` inside `__tests__` directory or alongside file.
|
|
|
|
### Error Handling
|
|
|
|
- Use try-catch for async operations.
|
|
- Provide meaningful error messages.
|
|
- Clean up resources (timers, event listeners) in `useEffect` cleanup.
|
|
|
|
### Testing
|
|
|
|
- Add `// @vitest-environment jsdom` at top of test files.
|
|
- Use `describe` and `it` blocks.
|
|
- Clean up after each test with `cleanup()` from `@testing-library/react`.
|
|
- Mock external dependencies appropriately.
|
|
- Test behavior, not implementation details.
|
|
|
|
```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(<Button aria-label="Submit">Click</Button>);
|
|
expect(screen.getByRole('button', { name: /submit/i })).toBeTruthy();
|
|
});
|
|
});
|
|
```
|
|
|
|
### Performance & Best Practices
|
|
|
|
- Use `React.lazy()` for code splitting on routes.
|
|
- Memoize expensive calculations with `useMemo`.
|
|
- Debounce expensive operations (use `debounce` utility).
|
|
- Always include `aria-label` for interactive elements if text is not descriptive.
|
|
- Ensure semantic HTML (`<nav>`, `<main>`, `<header>`).
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
src/
|
|
├── components/
|
|
│ ├── effects/ # Visual effects
|
|
│ ├── layout/ # Layout components
|
|
│ └── ui/ # Reusable UI components (Button, Input)
|
|
├── hooks/ # Custom React hooks
|
|
├── i18n/ # Internationalization
|
|
├── pages/ # Route components
|
|
├── styles/ # Global styles
|
|
└── utils/ # Utility functions
|
|
```
|