4.5 KiB
4.5 KiB
AGENTS.md - Coding Guidelines for RagusaIT Web
Build Commands
# 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.
# 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
# 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
typefor type definitions,interfacefor object shapes that may be extended. - Avoid
any- useunknownwhen type is uncertain. - Use
import typefor type-only imports when possible.
Imports (Order)
- React imports (
react,react-dom) - Third-party libraries (alphabetical, e.g.,
motion/react,react-icons) - Absolute imports from project (
@/components,@/utilsif configured, otherwise relative) - Relative imports (
../../utils) - CSS/SCSS imports last (
./Component.module.css)
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
motioncomponents (e.g.,motion.button) for animations.
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
useprefix (e.g.,useRateLimit) - Utilities: camelCase (e.g.,
debounce,formatDate) - Types/Interfaces: PascalCase (e.g.,
ButtonProps) - Files: Match default export name (e.g.,
Navbar.tsxexportsNavbar) - Test Files:
[Filename].test.tsxinside__tests__directory or alongside file.
Error Handling
- Use try-catch for async operations.
- Provide meaningful error messages.
- Clean up resources (timers, event listeners) in
useEffectcleanup.
Testing
- Add
// @vitest-environment jsdomat top of test files. - Use
describeanditblocks. - Clean up after each test with
cleanup()from@testing-library/react. - Mock external dependencies appropriately.
- Test behavior, not implementation details.
// @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
debounceutility). - Always include
aria-labelfor 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