shipdeck
Version:
Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.
1,139 lines (943 loc) • 30.3 kB
JavaScript
/**
* Frontend Agent for Shipdeck Ultimate
* Specializes in React/Next.js component generation, UI development, and frontend architecture
*/
const { BaseAgent } = require('./base-agent');
class FrontendAgent extends BaseAgent {
constructor(options = {}) {
super({
name: 'FrontendAgent',
description: 'Specialized agent for React/Next.js frontend development, UI components, and responsive design',
version: '1.0.0',
...options
});
// Frontend-specific configuration
this.frontendConfig = {
framework: 'react',
styling: 'tailwindcss',
stateManagement: 'hooks',
routing: 'next-router',
typescript: true,
accessibility: true,
responsive: true,
testing: true,
...options.frontendConfig
};
// Templates for different component types
this.templates = this.initializeTemplates();
}
/**
* Get frontend agent capabilities
* @returns {Array<string>} Array of frontend capabilities
*/
getCapabilities() {
return ['ui', 'components', 'styling', 'forms', 'navigation', 'responsive', 'accessibility', 'state-management'];
}
/**
* Initialize component generation templates
* @returns {Object} Templates object
*/
initializeTemplates() {
return {
react: {
functionalComponent: this.getFunctionalComponentTemplate(),
pageComponent: this.getPageComponentTemplate(),
formComponent: this.getFormComponentTemplate(),
navigationComponent: this.getNavigationTemplate(),
heroSection: this.getHeroSectionTemplate(),
cardGrid: this.getCardGridTemplate(),
modalDialog: this.getModalDialogTemplate(),
hooks: this.getHooksTemplate(),
tests: this.getTestTemplate()
}
};
}
/**
* Execute frontend development task
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated frontend code and structure
*/
async execute(task, context = {}) {
this.log('info', `Executing frontend task: ${task.type}`, { task: task.type });
try {
switch (task.type) {
case 'generate-component':
return await this.generateComponent(task, context);
case 'generate-page':
return await this.generatePage(task, context);
case 'generate-form':
return await this.generateForm(task, context);
case 'generate-navigation':
return await this.generateNavigation(task, context);
case 'generate-hero':
return await this.generateHero(task, context);
case 'generate-card-grid':
return await this.generateCardGrid(task, context);
case 'generate-modal':
return await this.generateModal(task, context);
case 'generate-layout':
return await this.generateLayout(task, context);
case 'generate-hooks':
return await this.generateHooks(task, context);
case 'generate-tests':
return await this.generateTests(task, context);
default:
return await this.generateCustomComponent(task, context);
}
} catch (error) {
this.log('error', `Frontend task execution failed: ${error.message}`, { error: error.stack });
throw error;
}
}
/**
* Generate React component
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated component code
*/
async generateComponent(task, context) {
const prompt = this.createComponentPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 8192,
temperature: 0.3
});
if (!response.success) {
throw new Error(`Component generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'component');
}
/**
* Generate Next.js page
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated page code
*/
async generatePage(task, context) {
const prompt = this.createPagePrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 8192,
temperature: 0.3
});
if (!response.success) {
throw new Error(`Page generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'page');
}
/**
* Generate form component with validation
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated form code
*/
async generateForm(task, context) {
const prompt = this.createFormPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 8192,
temperature: 0.2
});
if (!response.success) {
throw new Error(`Form generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'form');
}
/**
* Generate navigation component
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated navigation code
*/
async generateNavigation(task, context) {
const prompt = this.createNavigationPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.3
});
if (!response.success) {
throw new Error(`Navigation generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'navigation');
}
/**
* Generate hero section
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated hero section code
*/
async generateHero(task, context) {
const prompt = this.createHeroPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.4
});
if (!response.success) {
throw new Error(`Hero section generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'hero');
}
/**
* Generate card grid component
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated card grid code
*/
async generateCardGrid(task, context) {
const prompt = this.createCardGridPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.3
});
if (!response.success) {
throw new Error(`Card grid generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'card-grid');
}
/**
* Generate modal dialog
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated modal code
*/
async generateModal(task, context) {
const prompt = this.createModalPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.2
});
if (!response.success) {
throw new Error(`Modal generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'modal');
}
/**
* Generate layout component
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated layout code
*/
async generateLayout(task, context) {
const prompt = this.createLayoutPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 8192,
temperature: 0.3
});
if (!response.success) {
throw new Error(`Layout generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'layout');
}
/**
* Generate custom hooks
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated hooks code
*/
async generateHooks(task, context) {
const prompt = this.createHooksPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.2
});
if (!response.success) {
throw new Error(`Hooks generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'hooks');
}
/**
* Generate test suites for components
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated test code
*/
async generateTests(task, context) {
const prompt = this.createTestPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 6144,
temperature: 0.2
});
if (!response.success) {
throw new Error(`Test generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'tests');
}
/**
* Generate custom frontend code
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {Promise<Object>} Generated custom code
*/
async generateCustomComponent(task, context) {
const prompt = this.createCustomPrompt(task, context);
const response = await this.sendMessage(prompt, {
maxTokens: 8192,
temperature: 0.4
});
if (!response.success) {
throw new Error(`Custom component generation failed: ${response.error}`);
}
return this.parseFrontendResponse(response.content, 'custom');
}
/**
* Get system prompt for frontend agent
* @returns {string} System prompt
*/
getSystemPrompt() {
return `You are FrontendAgent, a specialized AI agent for React/Next.js frontend development.
CORE EXPERTISE:
- React functional components with hooks
- Next.js pages and app router
- TypeScript implementation
- Tailwind CSS styling
- Responsive design (mobile-first)
- Form handling and validation
- State management (hooks, Context, Zustand)
- Accessibility (WCAG guidelines)
- Performance optimization
- Component testing
CRITICAL RULES:
1. NEVER use 'any' type in TypeScript - use proper interfaces
2. Always use functional components with hooks
3. Implement proper loading and error states
4. Use semantic HTML elements for accessibility
5. Add ARIA labels and roles where needed
6. Implement mobile-first responsive design
7. Use proper form validation with error messages
8. Add comprehensive tests for all components
9. Follow React best practices (memoization, key props)
10. Implement proper error boundaries
11. Use 'use client' directive only when needed
12. Handle edge cases and empty states
STYLING STANDARDS:
- Use Tailwind CSS utility classes
- Implement consistent spacing system
- Use CSS Grid and Flexbox for layouts
- Add hover and focus states
- Use proper color contrast ratios
- Implement smooth transitions
COMPONENT STRUCTURE:
- TypeScript interfaces for props
- Default props and prop validation
- Proper component naming (PascalCase)
- Logical component composition
- Reusable and composable design
- Clean separation of concerns
RESPONSE FORMAT:
Always return code in structured format with:
- Complete TypeScript component files
- Proper folder structure
- Tailwind CSS styling
- Form validation logic
- Error handling
- Loading states
- Accessibility features
- Component tests
- Usage examples
Focus on creating delightful, accessible, and performant user interfaces.`;
}
/**
* Create component generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createComponentPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate React Component
COMPONENT SPECIFICATION:
- Name: ${task.componentName || 'CustomComponent'}
- Type: ${task.componentType || 'functional'}
- Framework: ${this.frontendConfig.framework}
- Styling: ${this.frontendConfig.styling}
- TypeScript: ${this.frontendConfig.typescript}
- Responsive: ${this.frontendConfig.responsive}
- Accessibility: ${this.frontendConfig.accessibility}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create reusable functional component'}
PROPS INTERFACE:
${task.props ? JSON.stringify(task.props, null, 2) : 'Define based on description'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete React component with:
1. TypeScript interface for props
2. Functional component with proper hooks
3. Tailwind CSS styling (responsive)
4. Accessibility features (ARIA labels, semantic HTML)
5. Loading and error states
6. Proper prop validation
7. Memoization where appropriate
8. Component tests with React Testing Library
9. Usage examples
10. Documentation comments
${this.templates.react.functionalComponent}`;
}
/**
* Create page generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createPagePrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Next.js Page
PAGE SPECIFICATION:
- Route: ${task.route || '/example'}
- Layout: ${task.layout || 'default'}
- Data Fetching: ${task.dataFetching || 'none'}
- SEO: ${task.seo !== false}
- Authentication: ${task.requiresAuth || false}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create Next.js page with proper structure'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete Next.js page with:
1. Page component with proper TypeScript
2. Meta tags and SEO optimization
3. Layout implementation
4. Data fetching (if needed)
5. Loading and error states
6. Responsive design
7. Accessibility features
8. Authentication checks (if required)
9. Tests for the page component
${this.templates.react.pageComponent}`;
}
/**
* Create form generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createFormPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Form Component
FORM SPECIFICATION:
- Fields: ${JSON.stringify(task.fields || {}, null, 2)}
- Validation: ${task.validation || 'client-side'}
- Submission: ${task.submission || 'async'}
- Reset: ${task.allowReset !== false}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create form with validation'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete form component with:
1. TypeScript interfaces for form data
2. Form state management with hooks
3. Input validation (real-time and on submit)
4. Error message display
5. Loading states during submission
6. Success/error feedback
7. Accessible form controls
8. Responsive design
9. Form reset functionality
10. Comprehensive tests
${this.templates.react.formComponent}`;
}
/**
* Create navigation generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createNavigationPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Navigation Component
NAVIGATION SPECIFICATION:
- Type: ${task.navType || 'header'}
- Menu Items: ${JSON.stringify(task.menuItems || [], null, 2)}
- Mobile Menu: ${task.mobileMenu !== false}
- Authentication: ${task.includeAuth || false}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create responsive navigation'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete navigation component with:
1. Responsive design (desktop and mobile)
2. Mobile hamburger menu
3. Active route highlighting
4. Accessibility features (keyboard navigation)
5. Smooth animations
6. Authentication integration (if needed)
7. TypeScript interfaces
8. Tests for navigation functionality
${this.templates.react.navigationComponent}`;
}
/**
* Create hero section prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createHeroPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Hero Section
HERO SPECIFICATION:
- Style: ${task.heroStyle || 'centered'}
- Content: ${JSON.stringify(task.content || {}, null, 2)}
- CTA Buttons: ${task.ctaButtons !== false}
- Background: ${task.background || 'gradient'}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create engaging hero section'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete hero section with:
1. Compelling headline and copy
2. Call-to-action buttons
3. Responsive design
4. Beautiful background styling
5. Smooth animations on scroll
6. Accessibility features
7. SEO optimization
8. TypeScript interfaces
${this.templates.react.heroSection}`;
}
/**
* Create card grid prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createCardGridPrompt(task, context) {
return `${this.getSimplePrompt()}
TASK: Generate Card Grid Component
CARD GRID SPECIFICATION:
- Grid Columns: ${task.columns || 'responsive'}
- Card Type: ${task.cardType || 'product'}
- Data Source: ${task.dataSource || 'props'}
- Pagination: ${task.pagination || false}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create responsive card grid'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete card grid with:
1. Responsive grid layout
2. Individual card components
3. Loading skeletons
4. Empty state handling
5. Hover animations
6. Accessibility features
7. TypeScript interfaces
8. Tests for grid functionality
${this.templates.react.cardGrid}`;
}
/**
* Create modal generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createModalPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Modal Dialog
MODAL SPECIFICATION:
- Size: ${task.modalSize || 'medium'}
- Type: ${task.modalType || 'dialog'}
- Close Methods: ${task.closeMethods || 'button,overlay,escape'}
- Animation: ${task.animation !== false}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Create accessible modal dialog'}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
Generate a complete modal component with:
1. Portal rendering for proper stacking
2. Focus management and trap
3. Keyboard navigation (Escape to close)
4. Smooth open/close animations
5. Backdrop overlay with click to close
6. Responsive design
7. Accessibility features (ARIA roles)
8. TypeScript interfaces
9. Tests for modal behavior
${this.templates.react.modalDialog}`;
}
/**
* Create layout generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createLayoutPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Layout Component
LAYOUT SPECIFICATION:
- Type: ${task.layoutType || 'default'}
- Header: ${task.includeHeader !== false}
- Footer: ${task.includeFooter !== false}
- Sidebar: ${task.includeSidebar || false}
Generate a complete layout system with all components and responsive behavior.
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}`;
}
/**
* Create hooks generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createHooksPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Custom Hooks
HOOKS SPECIFICATION:
- Hook Types: ${task.hookTypes ? task.hookTypes.join(', ') : 'Data fetching, State management'}
- Return Values: ${JSON.stringify(task.returnValues || {}, null, 2)}
Generate custom React hooks with proper TypeScript and tests.
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
${this.templates.react.hooks}`;
}
/**
* Create test generation prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createTestPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: Generate Component Tests
TEST SPECIFICATION:
- Component: ${task.componentName || 'Component'}
- Test Types: ${task.testTypes ? task.testTypes.join(', ') : 'Unit tests, Integration tests'}
- Testing Library: React Testing Library
Generate comprehensive tests with good coverage.
${task.description ? `DESCRIPTION: ${task.description}` : ''}
CONTEXT:
${this.formatContextPrompt(context)}
${this.templates.react.tests}`;
}
/**
* Create custom component prompt
* @param {Object} task - Task configuration
* @param {Object} context - Execution context
* @returns {string} Formatted prompt
*/
createCustomPrompt(task, context) {
return `${this.getSystemPrompt()}
TASK: ${task.type}
${task.description ? `DESCRIPTION: ${task.description}` : ''}
REQUIREMENTS:
${task.requirements ? task.requirements.map(r => `- ${r}`).join('\n') : '- Follow React best practices'}
CONTEXT:
${this.formatContextPrompt(context)}
Generate frontend code that follows all best practices and accessibility guidelines.`;
}
/**
* Get simple system prompt for lighter tasks
* @returns {string} Simple system prompt
*/
getSimplePrompt() {
return `You are FrontendAgent, specialized in React/Next.js development.
Create production-ready components with TypeScript, Tailwind CSS, and proper accessibility.`;
}
/**
* Parse frontend response and structure it
* @param {string} response - AI response
* @param {string} type - Response type
* @returns {Object} Structured frontend code
*/
parseFrontendResponse(response, type) {
try {
// Try to parse as JSON first
const parsed = JSON.parse(response);
return {
type: 'structured',
category: type,
code: parsed,
files: Object.keys(parsed),
timestamp: new Date().toISOString()
};
} catch {
// Parse as text with code extraction
const codeBlocks = this.extractCodeBlocks(response);
return {
type: 'text',
category: type,
content: response,
codeBlocks,
timestamp: new Date().toISOString()
};
}
}
/**
* Extract code blocks from text response
* @param {string} text - Response text
* @returns {Array} Array of code blocks
*/
extractCodeBlocks(text) {
const codeBlockRegex = /```(\w+)?\n([\s\S]*?)```/g;
const blocks = [];
let match;
while ((match = codeBlockRegex.exec(text)) !== null) {
blocks.push({
language: match[1] || 'typescript',
code: match[2].trim()
});
}
return blocks;
}
/**
* Get functional component template
* @returns {string} Functional component template
*/
getFunctionalComponentTemplate() {
return `
TEMPLATE: React Functional Component
import React from 'react';
interface ComponentProps {
// Define props interface
}
const Component: React.FC<ComponentProps> = ({ ...props }) => {
// Component logic with hooks
return (
<div className="component-container">
{/* JSX with Tailwind CSS */}
</div>
);
};
export default Component;
`;
}
/**
* Get page component template
* @returns {string} Page component template
*/
getPageComponentTemplate() {
return `
TEMPLATE: Next.js Page Component
import Head from 'next/head';
import { NextPage } from 'next';
interface PageProps {
// Define page props
}
const Page: NextPage<PageProps> = (props) => {
return (
<>
<Head>
<title>Page Title</title>
<meta name="description" content="Page description" />
</Head>
<main className="min-h-screen">
{/* Page content */}
</main>
</>
);
};
export default Page;
`;
}
/**
* Get form component template
* @returns {string} Form component template
*/
getFormComponentTemplate() {
return `
TEMPLATE: Form Component with Validation
import React, { useState } from 'react';
interface FormData {
// Define form data structure
}
interface FormComponentProps {
onSubmit: (data: FormData) => Promise<void>;
}
const FormComponent: React.FC<FormComponentProps> = ({ onSubmit }) => {
const [formData, setFormData] = useState<FormData>({});
const [errors, setErrors] = useState<Record<string, string>>({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
// Validation and submission logic
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
{/* Form fields with validation */}
</form>
);
};
export default FormComponent;
`;
}
/**
* Get navigation template
* @returns {string} Navigation template
*/
getNavigationTemplate() {
return `
TEMPLATE: Navigation Component
import React, { useState } from 'react';
import Link from 'next/link';
interface NavigationProps {
menuItems: Array<{ label: string; href: string; }>;
}
const Navigation: React.FC<NavigationProps> = ({ menuItems }) => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
return (
<nav className="bg-white shadow-lg">
<div className="max-w-7xl mx-auto px-4">
{/* Navigation content with mobile responsiveness */}
</div>
</nav>
);
};
export default Navigation;
`;
}
/**
* Get hero section template
* @returns {string} Hero section template
*/
getHeroSectionTemplate() {
return `
TEMPLATE: Hero Section
import React from 'react';
interface HeroProps {
title: string;
subtitle: string;
ctaText?: string;
onCTAClick?: () => void;
}
const Hero: React.FC<HeroProps> = ({ title, subtitle, ctaText, onCTAClick }) => {
return (
<section className="bg-gradient-to-r from-blue-600 to-purple-600 text-white">
<div className="max-w-7xl mx-auto px-4 py-20">
{/* Hero content */}
</div>
</section>
);
};
export default Hero;
`;
}
/**
* Get card grid template
* @returns {string} Card grid template
*/
getCardGridTemplate() {
return `
TEMPLATE: Card Grid Component
import React from 'react';
interface CardData {
id: string;
// Define card data structure
}
interface CardGridProps {
cards: CardData[];
loading?: boolean;
}
const CardGrid: React.FC<CardGridProps> = ({ cards, loading }) => {
if (loading) {
return <CardGridSkeleton />;
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{cards.map((card) => (
<Card key={card.id} data={card} />
))}
</div>
);
};
export default CardGrid;
`;
}
/**
* Get modal dialog template
* @returns {string} Modal dialog template
*/
getModalDialogTemplate() {
return `
TEMPLATE: Modal Dialog
import React, { useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
interface ModalProps {
isOpen: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
}
const Modal: React.FC<ModalProps> = ({ isOpen, onClose, title, children }) => {
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Focus management and event listeners
}, [isOpen]);
if (!isOpen) return null;
return createPortal(
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div className="fixed inset-0 bg-black bg-opacity-50" onClick={onClose} />
<div ref={modalRef} className="relative bg-white rounded-lg shadow-xl">
{/* Modal content */}
</div>
</div>,
document.body
);
};
export default Modal;
`;
}
/**
* Get hooks template
* @returns {string} Hooks template
*/
getHooksTemplate() {
return `
TEMPLATE: Custom React Hooks
import { useState, useEffect } from 'react';
// Custom hook example
export function useCustomHook<T>(initialValue: T) {
const [value, setValue] = useState<T>(initialValue);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Hook logic
return {
value,
loading,
error,
setValue,
// Other returned values
};
}
`;
}
/**
* Get test template
* @returns {string} Test template
*/
getTestTemplate() {
return `
TEMPLATE: Component Tests
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import Component from './Component';
describe('Component', () => {
beforeEach(() => {
// Test setup
});
afterEach(() => {
// Test cleanup
});
it('renders correctly', () => {
render(<Component />);
expect(screen.getByRole('button')).toBeInTheDocument();
});
it('handles user interactions', async () => {
render(<Component />);
const button = screen.getByRole('button');
fireEvent.click(button);
await waitFor(() => {
expect(screen.getByText('Success')).toBeInTheDocument();
});
});
it('handles error states', () => {
// Error state testing
});
});
`;
}
}
module.exports = FrontendAgent;