Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:56:35 +08:00
commit 0b8dfef442
16 changed files with 5044 additions and 0 deletions

View File

@@ -0,0 +1,510 @@
# /specweave-frontend:component-generate
Generate React/Vue/Angular components with tests, stories, and documentation following Atomic Design principles.
You are an expert frontend developer who creates well-structured, tested, and documented components.
## Your Task
Generate production-ready components with complete test coverage, Storybook stories, and documentation.
### 1. Component Types
**Atomic Design Levels**:
- **Atoms**: Basic UI elements (Button, Input, Icon, Text, Badge)
- **Molecules**: Simple component combinations (FormField, SearchBar, Card)
- **Organisms**: Complex components (Header, Form, DataTable, Modal)
- **Templates**: Page layouts (DashboardLayout, AuthLayout)
### 2. React Component Template
**TypeScript with Props Interface**:
```typescript
import React from 'react';
import { cn } from '@/lib/utils';
export interface CardProps {
/**
* Card title
*/
title?: string;
/**
* Card content
*/
children: React.ReactNode;
/**
* Card variant style
*/
variant?: 'default' | 'outlined' | 'elevated';
/**
* Optional footer content
*/
footer?: React.ReactNode;
/**
* Additional CSS classes
*/
className?: string;
/**
* Click handler
*/
onClick?: () => void;
}
export const Card = React.forwardRef<HTMLDivElement, CardProps>(
({ title, children, variant = 'default', footer, className, onClick }, ref) => {
const baseStyles = 'rounded-lg p-6 transition-all';
const variants = {
default: 'bg-white border border-gray-200',
outlined: 'bg-transparent border-2 border-gray-300',
elevated: 'bg-white shadow-lg hover:shadow-xl',
};
return (
<div
ref={ref}
className={cn(
baseStyles,
variants[variant],
onClick && 'cursor-pointer hover:border-blue-500',
className
)}
onClick={onClick}
>
{title && (
<h3 className="text-lg font-semibold mb-4 text-gray-900">{title}</h3>
)}
<div className="text-gray-700">{children}</div>
{footer && (
<div className="mt-4 pt-4 border-t border-gray-200">{footer}</div>
)}
</div>
);
}
);
Card.displayName = 'Card';
```
### 3. Component Test Template
**Comprehensive Testing**:
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { Card } from './Card';
describe('Card', () => {
describe('Rendering', () => {
it('renders children correctly', () => {
render(<Card>Test content</Card>);
expect(screen.getByText('Test content')).toBeInTheDocument();
});
it('renders title when provided', () => {
render(<Card title="Test Title">Content</Card>);
expect(screen.getByText('Test Title')).toBeInTheDocument();
});
it('renders footer when provided', () => {
render(
<Card footer={<button>Action</button>}>
Content
</Card>
);
expect(screen.getByText('Action')).toBeInTheDocument();
});
});
describe('Variants', () => {
it('applies default variant styles', () => {
const { container } = render(<Card>Content</Card>);
expect(container.firstChild).toHaveClass('bg-white', 'border-gray-200');
});
it('applies outlined variant styles', () => {
const { container } = render(<Card variant="outlined">Content</Card>);
expect(container.firstChild).toHaveClass('border-2');
});
it('applies elevated variant styles', () => {
const { container } = render(<Card variant="elevated">Content</Card>);
expect(container.firstChild).toHaveClass('shadow-lg');
});
});
describe('Interactions', () => {
it('handles click events', () => {
const onClick = vi.fn();
render(<Card onClick={onClick}>Content</Card>);
fireEvent.click(screen.getByText('Content'));
expect(onClick).toHaveBeenCalledTimes(1);
});
it('applies hover styles when clickable', () => {
const { container } = render(<Card onClick={() => {}}>Content</Card>);
expect(container.firstChild).toHaveClass('cursor-pointer');
});
});
describe('Accessibility', () => {
it('forwards ref correctly', () => {
const ref = React.createRef<HTMLDivElement>();
render(<Card ref={ref}>Content</Card>);
expect(ref.current).toBeInstanceOf(HTMLDivElement);
});
});
});
```
### 4. Storybook Stories Template
**Interactive Documentation**:
```typescript
import type { Meta, StoryObj } from '@storybook/react';
import { Card } from './Card';
const meta: Meta<typeof Card> = {
title: 'Molecules/Card',
component: Card,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'outlined', 'elevated'],
description: 'Visual variant of the card',
},
onClick: {
action: 'clicked',
},
},
decorators: [
(Story) => (
<div className="p-8 bg-gray-50">
<Story />
</div>
),
],
};
export default meta;
type Story = StoryObj<typeof Card>;
export const Default: Story = {
args: {
children: 'This is a default card with some content.',
},
};
export const WithTitle: Story = {
args: {
title: 'Card Title',
children: 'Card content goes here with a title above.',
},
};
export const WithFooter: Story = {
args: {
title: 'Card with Footer',
children: 'Main content area',
footer: <button className="text-blue-600 hover:underline">Learn more</button>,
},
};
export const Outlined: Story = {
args: {
variant: 'outlined',
title: 'Outlined Card',
children: 'This card has an outlined style.',
},
};
export const Elevated: Story = {
args: {
variant: 'elevated',
title: 'Elevated Card',
children: 'This card has a shadow elevation effect.',
},
};
export const Clickable: Story = {
args: {
title: 'Clickable Card',
children: 'Click me to trigger an action!',
onClick: () => alert('Card clicked!'),
},
};
export const Complex: Story = {
args: {
title: 'User Profile',
variant: 'elevated',
children: (
<div className="space-y-2">
<p className="text-sm text-gray-600">John Doe</p>
<p className="text-xs text-gray-500">john.doe@example.com</p>
<div className="flex gap-2 mt-4">
<span className="px-2 py-1 bg-blue-100 text-blue-800 rounded text-xs">Admin</span>
<span className="px-2 py-1 bg-green-100 text-green-800 rounded text-xs">Active</span>
</div>
</div>
),
footer: (
<button className="w-full py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
View Profile
</button>
),
},
};
```
### 5. Vue 3 Component Template (Composition API)
```vue
<script setup lang="ts">
import { computed } from 'vue';
export interface CardProps {
title?: string;
variant?: 'default' | 'outlined' | 'elevated';
footer?: boolean;
}
const props = withDefaults(defineProps<CardProps>(), {
variant: 'default',
footer: false,
});
const emit = defineEmits<{
click: [];
}>();
const cardClasses = computed(() => {
const base = 'rounded-lg p-6 transition-all';
const variants = {
default: 'bg-white border border-gray-200',
outlined: 'bg-transparent border-2 border-gray-300',
elevated: 'bg-white shadow-lg hover:shadow-xl',
};
return `${base} ${variants[props.variant]}`;
});
const handleClick = () => {
emit('click');
};
</script>
<template>
<div :class="cardClasses" @click="handleClick">
<h3 v-if="title" class="text-lg font-semibold mb-4 text-gray-900">
{{ title }}
</h3>
<div class="text-gray-700">
<slot />
</div>
<div v-if="footer || $slots.footer" class="mt-4 pt-4 border-t border-gray-200">
<slot name="footer" />
</div>
</div>
</template>
```
### 6. Angular Component Template
**TypeScript**:
```typescript
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { CommonModule } from '@angular/common';
export type CardVariant = 'default' | 'outlined' | 'elevated';
@Component({
selector: 'app-card',
standalone: true,
imports: [CommonModule],
templateUrl: './card.component.html',
styleUrls: ['./card.component.css'],
})
export class CardComponent {
@Input() title?: string;
@Input() variant: CardVariant = 'default';
@Input() footer?: string;
@Output() cardClick = new EventEmitter<void>();
get cardClasses(): string {
const base = 'rounded-lg p-6 transition-all';
const variants = {
default: 'bg-white border border-gray-200',
outlined: 'bg-transparent border-2 border-gray-300',
elevated: 'bg-white shadow-lg hover:shadow-xl',
};
return `${base} ${variants[this.variant]}`;
}
onClick(): void {
this.cardClick.emit();
}
}
```
**HTML**:
```html
<div [class]="cardClasses" (click)="onClick()">
<h3 *ngIf="title" class="text-lg font-semibold mb-4 text-gray-900">
{{ title }}
</h3>
<div class="text-gray-700">
<ng-content></ng-content>
</div>
<div *ngIf="footer" class="mt-4 pt-4 border-t border-gray-200">
<ng-content select="[footer]"></ng-content>
</div>
</div>
```
### 7. Component Documentation Template
**README.md**:
```markdown
# Card Component
A versatile card container component with multiple variants and optional footer.
## Features
- Multiple visual variants (default, outlined, elevated)
- Optional title and footer sections
- Clickable with hover effects
- Fully typed with TypeScript
- Responsive and accessible
- Comprehensive test coverage
## Usage
### React
\`\`\`tsx
import { Card } from '@/components/molecules/Card';
<Card title="Welcome" variant="elevated" onClick={handleClick}>
<p>Card content here</p>
</Card>
\`\`\`
### Vue 3
\`\`\`vue
<Card title="Welcome" variant="elevated" @click="handleClick">
<p>Card content here</p>
<template #footer>
<button>Action</button>
</template>
</Card>
\`\`\`
### Angular
\`\`\`html
<app-card title="Welcome" variant="elevated" (cardClick)="handleClick()">
<p>Card content here</p>
<div footer>
<button>Action</button>
</div>
</app-card>
\`\`\`
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| title | string | - | Optional card title |
| variant | 'default' \| 'outlined' \| 'elevated' | 'default' | Visual style variant |
| footer | ReactNode/slot | - | Optional footer content |
| onClick | function | - | Click handler |
## Examples
See Storybook for interactive examples and all variants.
## Accessibility
- Semantic HTML structure
- Keyboard navigation support
- ARIA labels where appropriate
- Color contrast compliance (WCAG AA)
## Testing
Run tests:
\`\`\`bash
npm test Card.test.tsx
\`\`\`
Coverage: 95%+ (statements, branches, functions, lines)
```
### 8. Component File Structure
```
components/{level}/{ComponentName}/
├── index.ts # Barrel export
├── {ComponentName}.tsx # Component implementation
├── {ComponentName}.test.tsx # Unit tests
├── {ComponentName}.stories.tsx # Storybook stories
├── {ComponentName}.module.css # Scoped styles (if not using Tailwind)
└── README.md # Documentation
```
### 9. Index Export
**index.ts**:
```typescript
export { Card } from './Card';
export type { CardProps } from './Card';
```
### 10. Component Checklist
Before considering a component complete:
- [ ] TypeScript interface with JSDoc comments
- [ ] All variants implemented and tested
- [ ] Unit tests with >80% coverage
- [ ] Storybook stories for all variants
- [ ] README documentation
- [ ] Accessibility compliance (ARIA, keyboard nav)
- [ ] Responsive design
- [ ] Error states handled
- [ ] Loading states (if applicable)
- [ ] Dark mode support (if applicable)
- [ ] Performance optimized (React.memo, useMemo)
## Workflow
1. Ask about component requirements (type, props, variants)
2. Determine Atomic Design level (atom/molecule/organism)
3. Generate component implementation
4. Create comprehensive unit tests
5. Add Storybook stories for all variants
6. Write documentation (README)
7. Implement accessibility features
8. Add to component index for easy imports
## Example Usage
**User**: "Generate a SearchBar molecule component with input and button"
**Response**:
Creates complete SearchBar component with:
- TypeScript implementation (React/Vue/Angular)
- Props interface (query, onSearch, placeholder, etc.)
- Unit tests (rendering, interactions, validation)
- Storybook stories (default, with results, loading state)
- README documentation
- Accessibility features (ARIA labels, keyboard shortcuts)
- Responsive design
## When to Use
- Creating new UI components
- Refactoring existing components to design system
- Building component libraries
- Ensuring consistent component structure
- Improving component documentation and testing
Generate production-ready components with complete tests and documentation!

View File

@@ -0,0 +1,494 @@
# /specweave-frontend:design-system-init
Initialize a complete design system with Atomic Design principles, design tokens, and component library.
You are an expert design system architect who creates scalable, maintainable component libraries.
## Your Task
Create a production-ready design system foundation with design tokens, theming, and Atomic Design component structure.
### 1. Design System Architecture
**Atomic Design Hierarchy**:
```
src/components/
├── atoms/ # Basic building blocks
│ ├── Button/
│ │ ├── Button.tsx
│ │ ├── Button.test.tsx
│ │ ├── Button.stories.tsx
│ │ └── index.ts
│ ├── Input/
│ ├── Text/
│ └── Icon/
├── molecules/ # Simple component groups
│ ├── FormField/ # Label + Input + Error
│ ├── SearchBar/ # Input + Button
│ └── Card/
├── organisms/ # Complex components
│ ├── Header/
│ ├── Footer/
│ ├── Form/
│ └── Navigation/
├── templates/ # Page layouts
│ ├── DashboardLayout/
│ ├── AuthLayout/
│ └── MarketingLayout/
└── pages/ # Full pages (if not using framework routing)
```
### 2. Design Tokens
**tokens/colors.ts**:
```typescript
export const colors = {
// Brand colors
brand: {
primary: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
900: '#1e3a8a',
},
secondary: {
50: '#f0fdf4',
500: '#22c55e',
900: '#14532d',
},
},
// Neutral colors
neutral: {
white: '#ffffff',
black: '#000000',
50: '#fafafa',
100: '#f5f5f5',
500: '#737373',
900: '#171717',
},
// Semantic colors
semantic: {
success: '#22c55e',
warning: '#f59e0b',
error: '#ef4444',
info: '#3b82f6',
},
} as const;
```
**tokens/typography.ts**:
```typescript
export const typography = {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['Roboto Mono', 'monospace'],
},
fontSize: {
xs: '0.75rem', // 12px
sm: '0.875rem', // 14px
base: '1rem', // 16px
lg: '1.125rem', // 18px
xl: '1.25rem', // 20px
'2xl': '1.5rem', // 24px
'3xl': '1.875rem', // 30px
'4xl': '2.25rem', // 36px
},
fontWeight: {
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
},
lineHeight: {
none: 1,
tight: 1.25,
normal: 1.5,
relaxed: 1.75,
},
} as const;
```
**tokens/spacing.ts**:
```typescript
export const spacing = {
0: '0',
1: '0.25rem', // 4px
2: '0.5rem', // 8px
3: '0.75rem', // 12px
4: '1rem', // 16px
5: '1.25rem', // 20px
6: '1.5rem', // 24px
8: '2rem', // 32px
10: '2.5rem', // 40px
12: '3rem', // 48px
16: '4rem', // 64px
20: '5rem', // 80px
} as const;
```
**tokens/index.ts**:
```typescript
export { colors } from './colors';
export { typography } from './typography';
export { spacing } from './spacing';
export { breakpoints } from './breakpoints';
export { shadows } from './shadows';
export { radii } from './radii';
export { transitions } from './transitions';
```
### 3. Theme Configuration
**theme/index.ts**:
```typescript
import { colors, typography, spacing } from '../tokens';
export const theme = {
colors,
typography,
spacing,
components: {
Button: {
variants: {
primary: {
bg: colors.brand.primary[500],
color: colors.neutral.white,
hover: {
bg: colors.brand.primary[600],
},
},
secondary: {
bg: 'transparent',
color: colors.brand.primary[500],
border: `1px solid ${colors.brand.primary[500]}`,
hover: {
bg: colors.brand.primary[50],
},
},
ghost: {
bg: 'transparent',
color: colors.neutral[700],
hover: {
bg: colors.neutral[100],
},
},
},
sizes: {
sm: {
height: '32px',
px: spacing[3],
fontSize: typography.fontSize.sm,
},
md: {
height: '40px',
px: spacing[4],
fontSize: typography.fontSize.base,
},
lg: {
height: '48px',
px: spacing[6],
fontSize: typography.fontSize.lg,
},
},
},
},
} as const;
export type Theme = typeof theme;
```
### 4. Component Template (Button)
**components/atoms/Button/Button.tsx**:
```typescript
import React from 'react';
import { cn } from '@/lib/utils';
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
isLoading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
children,
variant = 'primary',
size = 'md',
isLoading = false,
leftIcon,
rightIcon,
className,
disabled,
...props
},
ref
) => {
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2';
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
secondary: 'border border-blue-600 text-blue-600 hover:bg-blue-50 focus:ring-blue-500',
ghost: 'text-gray-700 hover:bg-gray-100 focus:ring-gray-500',
danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
};
const sizes = {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg',
};
return (
<button
ref={ref}
className={cn(
baseStyles,
variants[variant],
sizes[size],
(disabled || isLoading) && 'opacity-50 cursor-not-allowed',
className
)}
disabled={disabled || isLoading}
{...props}
>
{isLoading && <LoadingSpinner className="mr-2" />}
{!isLoading && leftIcon && <span className="mr-2">{leftIcon}</span>}
{children}
{!isLoading && rightIcon && <span className="ml-2">{rightIcon}</span>}
</button>
);
}
);
Button.displayName = 'Button';
```
**components/atoms/Button/Button.test.tsx**:
```typescript
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders correctly', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('handles click events', () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Click me</Button>);
fireEvent.click(screen.getByText('Click me'));
expect(onClick).toHaveBeenCalledTimes(1);
});
it('shows loading state', () => {
render(<Button isLoading>Click me</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
it('applies variant styles', () => {
const { rerender } = render(<Button variant="primary">Primary</Button>);
expect(screen.getByRole('button')).toHaveClass('bg-blue-600');
rerender(<Button variant="secondary">Secondary</Button>);
expect(screen.getByRole('button')).toHaveClass('border-blue-600');
});
});
```
### 5. Storybook Integration
**components/atoms/Button/Button.stories.tsx**:
```typescript
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Atoms/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'ghost', 'danger'],
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
},
},
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Primary Button',
},
};
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'Secondary Button',
},
};
export const Loading: Story = {
args: {
variant: 'primary',
isLoading: true,
children: 'Loading...',
},
};
export const WithIcons: Story = {
args: {
variant: 'primary',
leftIcon: <IconPlus />,
children: 'Add Item',
},
};
```
### 6. Utility Function (cn)
**lib/utils.ts**:
```typescript
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
```
### 7. TailwindCSS Configuration
**tailwind.config.ts**:
```typescript
import type { Config } from 'tailwindcss';
import { colors, typography, spacing } from './src/tokens';
const config: Config = {
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
theme: {
extend: {
colors: {
brand: colors.brand,
neutral: colors.neutral,
},
fontFamily: typography.fontFamily,
fontSize: typography.fontSize,
spacing,
},
},
plugins: [],
};
export default config;
```
### 8. Documentation Template
**components/atoms/Button/README.md**:
```markdown
# Button Component
A versatile button component with multiple variants and sizes.
## Usage
\`\`\`tsx
import { Button } from '@/components/atoms/Button';
<Button variant="primary" size="md" onClick={handleClick}>
Click me
</Button>
\`\`\`
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | 'primary' \| 'secondary' \| 'ghost' \| 'danger' | 'primary' | Button style variant |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Button size |
| isLoading | boolean | false | Shows loading spinner |
| leftIcon | ReactNode | - | Icon before text |
| rightIcon | ReactNode | - | Icon after text |
## Examples
See Storybook for interactive examples.
```
### 9. Essential Dependencies
```json
{
"dependencies": {
"clsx": "^2.0.0",
"tailwind-merge": "^2.0.0"
},
"devDependencies": {
"@storybook/react": "^7.6.0",
"@testing-library/react": "^14.0.0",
"tailwindcss": "^3.4.0"
}
}
```
### 10. Component Checklist
For each component, ensure:
- [ ] TypeScript props interface with JSDoc
- [ ] Accessibility (ARIA labels, keyboard navigation)
- [ ] Unit tests (>80% coverage)
- [ ] Storybook stories
- [ ] README documentation
- [ ] Responsive design
- [ ] Dark mode support (if applicable)
- [ ] Performance optimized (React.memo if needed)
## Workflow
1. Ask about design system requirements (brand colors, components needed)
2. Generate design tokens (colors, typography, spacing)
3. Set up theme configuration
4. Create component structure (Atomic Design)
5. Implement essential atoms (Button, Input, Text, Icon)
6. Add Storybook for component documentation
7. Configure Tailwind with design tokens
8. Provide usage guidelines and examples
## Example Usage
**User**: "Initialize a design system with blue brand color and Atomic Design"
**Response**:
Creates complete design system with:
- Design tokens (colors, typography, spacing)
- Theme configuration
- Atomic Design component structure
- Button, Input, Text components
- Storybook setup
- TailwindCSS integration
- Testing setup
- Documentation templates
## When to Use
- Starting new design systems
- Standardizing component libraries
- Rebranding existing applications
- Creating white-label products
- Building component libraries for teams
Build scalable, maintainable design systems with Atomic Design principles!

View File

@@ -0,0 +1,207 @@
# /specweave-frontend:frontend-scaffold
Scaffold a complete frontend project with modern tooling and best practices.
You are an expert frontend architect who creates production-ready project structures.
## Your Task
Generate a complete frontend project scaffold based on the user's requirements. Support React, Vue, Angular, and Next.js with modern tooling.
### 1. Supported Frameworks
**React**:
- TypeScript + Vite
- ESLint + Prettier
- Vitest + React Testing Library
- TailwindCSS or styled-components
- React Router v6
- React Query for data fetching
**Next.js 14+**:
- App Router (default)
- TypeScript
- TailwindCSS
- Server Components
- Route Handlers
- Metadata API
**Vue 3**:
- TypeScript + Vite
- Composition API
- Vue Router v4
- Pinia for state management
- Vitest
**Angular 17+**:
- Standalone Components
- TypeScript (strict)
- Angular Material
- RxJS
- Jest
### 2. Project Structure
**React/Next.js**:
```
src/
├── app/ # Next.js App Router
│ ├── layout.tsx
│ ├── page.tsx
│ └── api/
├── components/
│ ├── atoms/ # Atomic Design
│ ├── molecules/
│ ├── organisms/
│ └── templates/
├── hooks/
├── lib/
│ ├── api/
│ ├── utils/
│ └── constants/
├── styles/
│ └── globals.css
└── types/
```
**Vue**:
```
src/
├── components/
├── composables/
├── router/
├── stores/
├── views/
├── assets/
└── types/
```
### 3. Configuration Files
Generate these essential config files:
**TypeScript** (`tsconfig.json`):
```json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
```
**ESLint** (`.eslintrc.json`):
- TypeScript rules
- React Hooks rules
- Accessibility rules (jsx-a11y)
- Import ordering
**Prettier** (`.prettierrc`):
- Consistent formatting
- Tailwind plugin if using Tailwind
**Vite/Next Config**:
- Path aliases
- Environment variables
- Build optimization
### 4. Essential Dependencies
**Core**:
```json
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.3.0",
"vite": "^5.0.0"
}
}
```
**State Management**:
- Zustand (lightweight)
- Redux Toolkit (complex state)
- React Query (server state)
**Styling**:
- TailwindCSS (utility-first)
- styled-components (CSS-in-JS)
- CSS Modules (scoped styles)
**Testing**:
- Vitest (unit tests)
- React Testing Library
- Playwright (E2E)
### 5. Features to Include
1. **TypeScript Configuration**: Strict mode, path aliases
2. **Linting & Formatting**: ESLint, Prettier, Husky pre-commit hooks
3. **Testing Setup**: Unit test framework + E2E setup
4. **CI/CD**: GitHub Actions workflow
5. **Environment Management**: `.env` files for different environments
6. **Error Handling**: Error boundaries, global error handling
7. **Loading States**: Skeleton loaders, suspense boundaries
8. **Routing**: File-based (Next.js) or configured routing
9. **API Integration**: Fetch wrapper, error handling, typing
10. **Performance**: Code splitting, lazy loading, memoization
### 6. Best Practices
- **Component Organization**: Atomic Design pattern
- **Type Safety**: No `any` types, strict mode
- **Accessibility**: ARIA labels, keyboard navigation
- **Performance**: React.memo, useMemo, useCallback
- **SEO**: Metadata, Open Graph tags (Next.js)
- **Security**: CSP headers, XSS prevention
- **Code Quality**: Consistent naming, clear structure
### 7. Workflow
1. Ask about framework choice (React/Next/Vue/Angular)
2. Confirm styling approach (Tailwind/styled-components/CSS Modules)
3. Verify state management needs
4. Generate complete file structure
5. Create configuration files
6. Set up package.json with scripts
7. Provide setup instructions
## Example Usage
**User**: "Scaffold a Next.js 14 project with TailwindCSS and TypeScript"
**Response**:
Creates complete Next.js 14 App Router project with:
- TypeScript configuration
- TailwindCSS setup
- ESLint + Prettier
- Path aliases
- Testing setup
- CI/CD workflow
- Example components
## When to Use
- Starting new frontend projects
- Converting to TypeScript
- Modernizing legacy projects
- Setting up best practices
- Creating consistent team structure
Scaffold production-ready frontend projects with modern tooling and best practices!

396
commands/nextjs-setup.md Normal file
View File

@@ -0,0 +1,396 @@
# /specweave-frontend:nextjs-setup
Set up Next.js 14+ App Router project with modern best practices and production-ready configuration.
You are an expert Next.js architect specializing in the App Router, Server Components, and modern React patterns.
## Your Task
Configure a complete Next.js 14+ project with best practices for performance, SEO, and developer experience.
### 1. App Router Structure
Generate the following directory structure:
```
app/
├── layout.tsx # Root layout with metadata
├── page.tsx # Home page
├── loading.tsx # Loading UI
├── error.tsx # Error boundary
├── not-found.tsx # 404 page
├── global-error.tsx # Global error handler
├── api/ # API routes
│ └── hello/
│ └── route.ts
├── (marketing)/ # Route group
│ ├── about/
│ │ └── page.tsx
│ └── contact/
│ └── page.tsx
└── (dashboard)/ # Protected route group
├── layout.tsx
└── page.tsx
```
### 2. Root Layout Configuration
**app/layout.tsx**:
```typescript
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: {
default: 'App Name',
template: '%s | App Name',
},
description: 'App description',
metadataBase: new URL('https://example.com'),
openGraph: {
type: 'website',
locale: 'en_US',
url: 'https://example.com',
siteName: 'App Name',
},
twitter: {
card: 'summary_large_image',
creator: '@username',
},
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
```
### 3. Server Components Best Practices
**Data Fetching** (Server Component):
```typescript
// app/posts/page.tsx
async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 }, // ISR: Revalidate every hour
});
return res.json();
}
export default async function PostsPage() {
const posts = await getPosts();
return (
<div>
<h1>Posts</h1>
{posts.map((post) => (
<article key={post.id}>{post.title}</article>
))}
</div>
);
}
```
**Client Components** (for interactivity):
```typescript
'use client'; // Mark as Client Component
import { useState } from 'react';
export function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
```
### 4. API Routes (Route Handlers)
**app/api/hello/route.ts**:
```typescript
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const searchParams = request.nextUrl.searchParams;
const name = searchParams.get('name') || 'World';
return NextResponse.json({ message: `Hello, ${name}!` });
}
export async function POST(request: NextRequest) {
const body = await request.json();
// Process request
return NextResponse.json({ success: true, data: body });
}
```
### 5. Middleware Configuration
**middleware.ts** (root level):
```typescript
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Auth check
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
// Add custom headers
const response = NextResponse.next();
response.headers.set('x-custom-header', 'value');
return response;
}
export const config = {
matcher: ['/dashboard/:path*'],
};
```
### 6. next.config.js
```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'images.example.com',
},
],
},
experimental: {
typedRoutes: true, // Type-safe navigation
},
// Headers for security
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
],
},
];
},
};
module.exports = nextConfig;
```
### 7. Environment Variables
**.env.local**:
```bash
# Public (accessible in browser)
NEXT_PUBLIC_API_URL=https://api.example.com
# Private (server-only)
DATABASE_URL=postgresql://...
API_SECRET_KEY=...
```
**Usage**:
```typescript
// Server Component or API Route
const dbUrl = process.env.DATABASE_URL;
// Client Component
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
```
### 8. Performance Optimizations
**Dynamic Imports** (Code Splitting):
```typescript
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(() => import('@/components/HeavyComponent'), {
loading: () => <p>Loading...</p>,
ssr: false, // Disable SSR for this component
});
```
**Image Optimization**:
```typescript
import Image from 'next/image';
export function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // Load immediately
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
);
}
```
**Font Optimization**:
```typescript
import { Inter, Roboto_Mono } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
const robotoMono = Roboto_Mono({ subsets: ['latin'], variable: '--font-mono' });
// In layout
<body className={`${inter.variable} ${robotoMono.variable}`}>
```
### 9. Data Fetching Patterns
**Server Actions** (experimental):
```typescript
'use server';
export async function createPost(formData: FormData) {
const title = formData.get('title');
// Database operation
await db.post.create({ data: { title } });
revalidatePath('/posts');
redirect('/posts');
}
```
**Streaming with Suspense**:
```typescript
import { Suspense } from 'react';
export default function Page() {
return (
<div>
<h1>Dashboard</h1>
<Suspense fallback={<LoadingSkeleton />}>
<AsyncData />
</Suspense>
</div>
);
}
```
### 10. Essential Dependencies
```json
{
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "^5.3.0",
"eslint": "^8.0.0",
"eslint-config-next": "^14.0.0"
}
}
```
### 11. Deployment Configuration
**Vercel** (recommended):
- Automatic deployments from Git
- Edge Functions support
- Image Optimization CDN
- Analytics built-in
**Docker** (self-hosted):
```dockerfile
FROM node:20-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]
```
## Workflow
1. Ask about project requirements (API routes, auth, database, etc.)
2. Generate complete App Router structure
3. Set up metadata and SEO configuration
4. Configure middleware if needed
5. Create route groups for organization
6. Set up environment variables
7. Configure next.config.js
8. Provide setup and deployment instructions
## Example Usage
**User**: "Set up Next.js 14 with App Router and authentication"
**Response**:
Creates complete Next.js setup with:
- App Router structure with route groups
- Middleware for auth protection
- API routes for authentication
- Server and Client Components
- Metadata configuration
- Security headers
- Deployment configuration
## When to Use
- Starting new Next.js projects
- Migrating from Pages Router to App Router
- Setting up authentication flows
- Configuring SEO and metadata
- Optimizing performance
- Setting up API routes
Build production-ready Next.js applications with modern best practices!