feat: Add Cursor React example repo (Task 3.2)
Complete working example demonstrating Cursor + Skill Seekers workflow: **Main Example (examples/cursor-react-skill/):** - README.md (400+ lines) - Comprehensive guide with expected outputs - generate_cursorrules.py - Automation script for complete workflow - .cursorrules.example - Sample generated rules (React 18+ patterns) - requirements.txt - Python dependencies **Example Project (example-project/):** - package.json - React 18 + TypeScript + Vite - tsconfig.json - Strict TypeScript configuration - src/App.tsx - Sample counter component - src/index.tsx - React entry point - README.md - Testing instructions **Workflow Demonstrated:** 1. Scrape React docs → skill-seekers scrape 2. Package for Cursor → skill-seekers package --target claude 3. Extract and copy → unzip + cp to .cursorrules 4. Test in Cursor IDE with AI prompts **Example Prompts Included:** - useState hook patterns - Data fetching with useEffect - Custom hooks for validation - TypeScript typing examples Shows before/after comparison of AI suggestions with and without .cursorrules. Updates: README.md + INTEGRATIONS.md (added Haystack to supported list)
This commit is contained in:
@@ -17,7 +17,7 @@ English | [简体中文](https://github.com/yusufkaraaslan/Skill_Seekers/blob/ma
|
|||||||
[](https://x.com/_yUSyUS_)
|
[](https://x.com/_yUSyUS_)
|
||||||
[](https://github.com/yusufkaraaslan/Skill_Seekers)
|
[](https://github.com/yusufkaraaslan/Skill_Seekers)
|
||||||
|
|
||||||
**The universal preprocessor for any AI system: Convert documentation, GitHub repos, and PDFs into production-ready formats for LangChain, LlamaIndex, Pinecone, Cursor, Windsurf, Cline, Continue.dev, Claude, and any RAG pipeline—in minutes, not hours.**
|
**The universal preprocessor for any AI system: Convert documentation, GitHub repos, and PDFs into production-ready formats for LangChain, LlamaIndex, Haystack, Pinecone, Cursor, Windsurf, Cline, Continue.dev, Claude, and any RAG pipeline—in minutes, not hours.**
|
||||||
|
|
||||||
> 🌐 **[Visit SkillSeekersWeb.com](https://skillseekersweb.com/)** - Browse 24+ preset configs, share your configs, and access complete documentation!
|
> 🌐 **[Visit SkillSeekersWeb.com](https://skillseekersweb.com/)** - Browse 24+ preset configs, share your configs, and access complete documentation!
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ English | [简体中文](https://github.com/yusufkaraaslan/Skill_Seekers/blob/ma
|
|||||||
skill-seekers scrape --config configs/react.json
|
skill-seekers scrape --config configs/react.json
|
||||||
skill-seekers package output/react --target langchain # or llama-index, pinecone, cursor
|
skill-seekers package output/react --target langchain # or llama-index, pinecone, cursor
|
||||||
|
|
||||||
# 15 minutes → Ready for: LangChain, LlamaIndex, Pinecone, Cursor, Custom RAG
|
# 15 minutes → Ready for: LangChain, LlamaIndex, Haystack, Pinecone, Cursor, Custom RAG
|
||||||
```
|
```
|
||||||
|
|
||||||
### Supported Integrations
|
### Supported Integrations
|
||||||
@@ -41,6 +41,7 @@ skill-seekers package output/react --target langchain # or llama-index, pinecon
|
|||||||
|------------|--------|----------|-------|
|
|------------|--------|----------|-------|
|
||||||
| **LangChain** | `Documents` | QA chains, agents, retrievers | [Guide](docs/integrations/LANGCHAIN.md) |
|
| **LangChain** | `Documents` | QA chains, agents, retrievers | [Guide](docs/integrations/LANGCHAIN.md) |
|
||||||
| **LlamaIndex** | `TextNodes` | Query engines, chat engines | [Guide](docs/integrations/LLAMA_INDEX.md) |
|
| **LlamaIndex** | `TextNodes` | Query engines, chat engines | [Guide](docs/integrations/LLAMA_INDEX.md) |
|
||||||
|
| **Haystack** | `Documents` | Enterprise RAG pipelines | [Guide](docs/integrations/HAYSTACK.md) |
|
||||||
| **Pinecone** | Ready for upsert | Production vector search | [Guide](docs/integrations/PINECONE.md) |
|
| **Pinecone** | Ready for upsert | Production vector search | [Guide](docs/integrations/PINECONE.md) |
|
||||||
| **Cursor IDE** | `.cursorrules` | AI coding (VS Code fork) | [Guide](docs/integrations/CURSOR.md) |
|
| **Cursor IDE** | `.cursorrules` | AI coding (VS Code fork) | [Guide](docs/integrations/CURSOR.md) |
|
||||||
| **Windsurf** | `.windsurfrules` | AI coding (Codeium IDE) | [Guide](docs/integrations/WINDSURF.md) |
|
| **Windsurf** | `.windsurfrules` | AI coding (Codeium IDE) | [Guide](docs/integrations/WINDSURF.md) |
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Transform documentation into RAG-ready formats for AI-powered search and retriev
|
|||||||
|-----------|-------|--------|----------|-------|
|
|-----------|-------|--------|----------|-------|
|
||||||
| **[LangChain](LANGCHAIN.md)** | 500K+ | Document | Python RAG, most popular | [Setup →](LANGCHAIN.md) |
|
| **[LangChain](LANGCHAIN.md)** | 500K+ | Document | Python RAG, most popular | [Setup →](LANGCHAIN.md) |
|
||||||
| **[LlamaIndex](LLAMA_INDEX.md)** | 200K+ | TextNode | Q&A focus, query engine | [Setup →](LLAMA_INDEX.md) |
|
| **[LlamaIndex](LLAMA_INDEX.md)** | 200K+ | TextNode | Q&A focus, query engine | [Setup →](LLAMA_INDEX.md) |
|
||||||
| **[Haystack](HAYSTACK.md)** | 50K+ | Document | Enterprise, multi-language | *Coming in v2.11.0* |
|
| **[Haystack](HAYSTACK.md)** | 50K+ | Document | Enterprise, multi-language | [Setup →](HAYSTACK.md) |
|
||||||
|
|
||||||
**Quick Example:**
|
**Quick Example:**
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
171
examples/cursor-react-skill/.cursorrules.example
Normal file
171
examples/cursor-react-skill/.cursorrules.example
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
# React 18 Expert - Cursor Rules
|
||||||
|
|
||||||
|
You are an expert React 18+ developer with deep knowledge of modern patterns, TypeScript, and best practices.
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
- **Functional Components Only** - Use function components, never class components
|
||||||
|
- **Hooks-First** - useState, useEffect, useContext, useMemo, useCallback
|
||||||
|
- **TypeScript Strict** - Proper typing for props, state, events, refs
|
||||||
|
- **Performance** - Memoization, code splitting, lazy loading
|
||||||
|
- **Accessibility** - ARIA attributes, semantic HTML, keyboard navigation
|
||||||
|
|
||||||
|
## React Hooks Patterns
|
||||||
|
|
||||||
|
### useState
|
||||||
|
```tsx
|
||||||
|
const [state, setState] = useState<Type>(initialValue);
|
||||||
|
```
|
||||||
|
|
||||||
|
### useEffect
|
||||||
|
```tsx
|
||||||
|
useEffect(() => {
|
||||||
|
// Effect logic
|
||||||
|
return () => {
|
||||||
|
// Cleanup
|
||||||
|
};
|
||||||
|
}, [dependencies]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### useContext
|
||||||
|
```tsx
|
||||||
|
const value = useContext(MyContext);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Hooks
|
||||||
|
```tsx
|
||||||
|
function useCustomHook() {
|
||||||
|
const [state, setState] = useState();
|
||||||
|
// Logic
|
||||||
|
return { state, setState };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## TypeScript Best Practices
|
||||||
|
|
||||||
|
### Component Props
|
||||||
|
```tsx
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
count?: number;
|
||||||
|
onUpdate: (value: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MyComponent({ title, count = 0, onUpdate }: Props) {
|
||||||
|
// Component logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Events
|
||||||
|
```tsx
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
// Handle click
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
// Handle change
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Refs
|
||||||
|
```tsx
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Data Fetching
|
||||||
|
```tsx
|
||||||
|
function DataComponent() {
|
||||||
|
const [data, setData] = useState<Data[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch(url)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
setData(data);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
setError(err.message);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) return <LoadingSpinner />;
|
||||||
|
if (error) return <ErrorMessage error={error} />;
|
||||||
|
return <DataList data={data} />;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Form Handling
|
||||||
|
```tsx
|
||||||
|
function Form() {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
name: '',
|
||||||
|
email: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
[e.target.name]: e.target.value
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// Submit logic
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<input name="name" value={formData.name} onChange={handleChange} />
|
||||||
|
<input name="email" value={formData.email} onChange={handleChange} />
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
```tsx
|
||||||
|
// useMemo for expensive calculations
|
||||||
|
const expensiveValue = useMemo(() => {
|
||||||
|
return computeExpensiveValue(data);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
// useCallback for function references
|
||||||
|
const handleClick = useCallback(() => {
|
||||||
|
doSomething(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
// React.memo for component memoization
|
||||||
|
export const MemoizedComponent = React.memo(MyComponent);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Style
|
||||||
|
|
||||||
|
- Use arrow functions for components
|
||||||
|
- Destructure props immediately
|
||||||
|
- Use early returns for loading/error states
|
||||||
|
- Keep components small and focused
|
||||||
|
- Extract complex logic into custom hooks
|
||||||
|
- Use meaningful variable names
|
||||||
|
|
||||||
|
## Avoid
|
||||||
|
|
||||||
|
- ❌ Class components
|
||||||
|
- ❌ Inline function definitions in JSX
|
||||||
|
- ❌ Missing dependency arrays in useEffect
|
||||||
|
- ❌ Mutating state directly
|
||||||
|
- ❌ Props drilling (use Context instead)
|
||||||
|
- ❌ Missing TypeScript types
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- React Documentation: https://react.dev
|
||||||
|
- TypeScript + React: https://react.dev/learn/typescript
|
||||||
|
- React Hooks: https://react.dev/reference/react/hooks
|
||||||
366
examples/cursor-react-skill/README.md
Normal file
366
examples/cursor-react-skill/README.md
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
# Cursor + React Skill Example
|
||||||
|
|
||||||
|
Complete example showing how to use Skill Seekers to generate Cursor rules for React development.
|
||||||
|
|
||||||
|
## What This Example Does
|
||||||
|
|
||||||
|
- ✅ Generates React documentation skill
|
||||||
|
- ✅ Creates `.cursorrules` for Cursor IDE
|
||||||
|
- ✅ Shows AI-powered React code completion
|
||||||
|
- ✅ Includes sample React project
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Generate React Skill
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install Skill Seekers
|
||||||
|
pip install skill-seekers
|
||||||
|
|
||||||
|
# Generate React documentation skill
|
||||||
|
skill-seekers scrape --config configs/react.json --max-pages 100
|
||||||
|
|
||||||
|
# Package for Cursor
|
||||||
|
skill-seekers package output/react --target claude
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates `output/react-claude.zip` containing `SKILL.md` (the Cursor rules file).
|
||||||
|
|
||||||
|
### 2. Extract and Copy Rules
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Extract the ZIP
|
||||||
|
unzip output/react-claude.zip -d output/react-cursor
|
||||||
|
|
||||||
|
# Copy rules to your project
|
||||||
|
cp output/react-cursor/SKILL.md example-project/.cursorrules
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the automation script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python generate_cursorrules.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Test in Cursor
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Open project in Cursor
|
||||||
|
cursor example-project/
|
||||||
|
|
||||||
|
# Try these prompts in Cursor:
|
||||||
|
# - "Create a useState hook for managing user data"
|
||||||
|
# - "Add useEffect to fetch data on mount"
|
||||||
|
# - "Implement a custom hook for form validation"
|
||||||
|
# - "Create a component with proper TypeScript types"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected Results
|
||||||
|
|
||||||
|
### Before (Without .cursorrules)
|
||||||
|
|
||||||
|
- Generic React suggestions
|
||||||
|
- May use outdated patterns (class components, etc.)
|
||||||
|
- No TypeScript best practices
|
||||||
|
- Missing modern Hooks patterns
|
||||||
|
|
||||||
|
### After (With .cursorrules)
|
||||||
|
|
||||||
|
- React 18+ specific patterns
|
||||||
|
- Hooks-based architecture (useState, useEffect, custom hooks)
|
||||||
|
- TypeScript strict mode with proper types
|
||||||
|
- Modern best practices (functional components, composition)
|
||||||
|
- Context API and state management patterns
|
||||||
|
- Performance optimization (useMemo, useCallback)
|
||||||
|
|
||||||
|
## Automation Script
|
||||||
|
|
||||||
|
The `generate_cursorrules.py` script automates the entire workflow:
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Automate Cursor rules generation for React.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(cmd: list, description: str) -> bool:
|
||||||
|
"""Run a shell command and return success status."""
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"STEP: {description}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"❌ Error: {result.stderr}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"✅ Success!")
|
||||||
|
if result.stdout:
|
||||||
|
print(result.stdout)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run the automation workflow."""
|
||||||
|
print("=" * 60)
|
||||||
|
print("Cursor Rules Generator - React Example")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Step 1: Scrape React docs
|
||||||
|
if not run_command(
|
||||||
|
["skill-seekers", "scrape", "--config", "configs/react.json", "--max-pages", "100"],
|
||||||
|
"Scraping React documentation"
|
||||||
|
):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 2: Package for Cursor
|
||||||
|
if not run_command(
|
||||||
|
["skill-seekers", "package", "output/react", "--target", "claude"],
|
||||||
|
"Packaging for Cursor"
|
||||||
|
):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 3: Extract ZIP
|
||||||
|
if not run_command(
|
||||||
|
["unzip", "-o", "output/react-claude.zip", "-d", "output/react-cursor"],
|
||||||
|
"Extracting packaged skill"
|
||||||
|
):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 4: Copy to example project
|
||||||
|
source = Path("output/react-cursor/SKILL.md")
|
||||||
|
target = Path("example-project/.cursorrules")
|
||||||
|
|
||||||
|
if not source.exists():
|
||||||
|
print(f"❌ Error: {source} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_text(source.read_text())
|
||||||
|
|
||||||
|
print(f"\n✅ Copied rules to {target}")
|
||||||
|
|
||||||
|
# Success summary
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("✅ Cursor rules generated successfully!")
|
||||||
|
print("=" * 60)
|
||||||
|
print(f"\n📁 Rules file: {target.absolute()}")
|
||||||
|
print("\n🚀 Next steps:")
|
||||||
|
print(" 1. Open example-project/ in Cursor")
|
||||||
|
print(" 2. Try the example prompts in the README")
|
||||||
|
print(" 3. Compare AI suggestions before/after")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n\n⚠️ Interrupted by user")
|
||||||
|
sys.exit(0)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sample .cursorrules File
|
||||||
|
|
||||||
|
See `.cursorrules.example` for a sample generated rules file. Key sections include:
|
||||||
|
|
||||||
|
- **React Fundamentals** - Components, JSX, props, state
|
||||||
|
- **Hooks** - useState, useEffect, useContext, custom hooks
|
||||||
|
- **TypeScript** - Proper typing for components, props, events
|
||||||
|
- **Performance** - useMemo, useCallback, React.memo
|
||||||
|
- **Best Practices** - Component composition, error boundaries
|
||||||
|
- **Common Patterns** - Forms, data fetching, routing
|
||||||
|
|
||||||
|
## Example Project Structure
|
||||||
|
|
||||||
|
The `example-project/` directory contains a minimal React + TypeScript setup:
|
||||||
|
|
||||||
|
```
|
||||||
|
example-project/
|
||||||
|
├── .cursorrules # Generated rules (empty initially)
|
||||||
|
├── package.json # React + TypeScript dependencies
|
||||||
|
├── tsconfig.json # TypeScript configuration
|
||||||
|
├── src/
|
||||||
|
│ ├── App.tsx # Main component
|
||||||
|
│ └── index.tsx # Entry point
|
||||||
|
└── README.md # Project-specific instructions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing the AI
|
||||||
|
|
||||||
|
Open `example-project/` in Cursor and try these prompts:
|
||||||
|
|
||||||
|
**1. useState Hook:**
|
||||||
|
```
|
||||||
|
Create a counter component with increment and decrement buttons
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output with .cursorrules:**
|
||||||
|
```tsx
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export function Counter() {
|
||||||
|
const [count, setCount] = useState<number>(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<button onClick={() => setCount(count + 1)}>Increment</button>
|
||||||
|
<button onClick={() => setCount(count - 1)}>Decrement</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Data Fetching:**
|
||||||
|
```
|
||||||
|
Create a component that fetches user data from an API
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output with .cursorrules:**
|
||||||
|
```tsx
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function UserList() {
|
||||||
|
const [users, setUsers] = useState<User[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('https://api.example.com/users')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
setUsers(data);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
setError(err.message);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) return <div>Loading...</div>;
|
||||||
|
if (error) return <div>Error: {error}</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{users.map(user => (
|
||||||
|
<li key={user.id}>{user.name} - {user.email}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Custom Hook:**
|
||||||
|
```
|
||||||
|
Create a custom hook for form validation
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected output with .cursorrules:**
|
||||||
|
```tsx
|
||||||
|
import { useState, useCallback } from 'react';
|
||||||
|
|
||||||
|
interface ValidationRules {
|
||||||
|
[field: string]: (value: string) => string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useFormValidation(rules: ValidationRules) {
|
||||||
|
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||||
|
|
||||||
|
const validate = useCallback((field: string, value: string) => {
|
||||||
|
const error = rules[field]?.(value);
|
||||||
|
setErrors(prev => ({
|
||||||
|
...prev,
|
||||||
|
[field]: error || ''
|
||||||
|
}));
|
||||||
|
return !error;
|
||||||
|
}, [rules]);
|
||||||
|
|
||||||
|
const validateAll = useCallback((values: Record<string, string>) => {
|
||||||
|
const newErrors: Record<string, string> = {};
|
||||||
|
let isValid = true;
|
||||||
|
|
||||||
|
for (const field in rules) {
|
||||||
|
const error = rules[field](values[field] || '');
|
||||||
|
if (error) {
|
||||||
|
newErrors[field] = error;
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(newErrors);
|
||||||
|
return isValid;
|
||||||
|
}, [rules]);
|
||||||
|
|
||||||
|
return { errors, validate, validateAll };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files in This Example
|
||||||
|
|
||||||
|
- `README.md` - This file
|
||||||
|
- `generate_cursorrules.py` - Automation script
|
||||||
|
- `.cursorrules.example` - Sample generated rules
|
||||||
|
- `example-project/` - Minimal React + TypeScript project
|
||||||
|
- `requirements.txt` - Python dependencies (skill-seekers)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Issue: Rules not loading
|
||||||
|
|
||||||
|
**Solution:** Restart Cursor IDE or reload window (Cmd+Shift+P → "Reload Window")
|
||||||
|
|
||||||
|
### Issue: AI not using rules
|
||||||
|
|
||||||
|
**Solution:** Check `.cursorrules` is at project root. Verify with AI: "Are you aware of .cursorrules?"
|
||||||
|
|
||||||
|
### Issue: skill-seekers not found
|
||||||
|
|
||||||
|
**Solution:** Install Skill Seekers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install skill-seekers
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue: Scraping fails
|
||||||
|
|
||||||
|
**Solution:** Check internet connection, or use smaller --max-pages value
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skill-seekers scrape --config configs/react.json --max-pages 50
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. Customize rules for your project needs
|
||||||
|
2. Add project-specific patterns to `.cursorrules`
|
||||||
|
3. Include internal component library documentation
|
||||||
|
4. Share with team for consistency
|
||||||
|
5. Try other frameworks (Vue, Angular, Django, etc.)
|
||||||
|
|
||||||
|
## Related Examples
|
||||||
|
|
||||||
|
- [Windsurf Example](../windsurf-fastapi-context/)
|
||||||
|
- [Cline Example](../cline-django-assistant/)
|
||||||
|
- [Continue.dev Example](../continue-dev-universal/)
|
||||||
|
- [LangChain RAG Example](../langchain-rag-pipeline/)
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Cursor Documentation](https://cursor.sh/docs)
|
||||||
|
- [Cursor Rules Guide](https://cursor.sh/docs/cursorrules)
|
||||||
|
- [Skill Seekers Documentation](https://github.com/yusufkaraaslan/Skill_Seekers)
|
||||||
|
- [React Documentation](https://react.dev/)
|
||||||
43
examples/cursor-react-skill/example-project/README.md
Normal file
43
examples/cursor-react-skill/example-project/README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Example React Project for Cursor
|
||||||
|
|
||||||
|
Minimal React + TypeScript project to test Cursor AI with `.cursorrules`.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Start development server
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Cursor AI
|
||||||
|
|
||||||
|
Once you have `.cursorrules` in this directory, try these prompts in Cursor:
|
||||||
|
|
||||||
|
### Basic Hooks
|
||||||
|
- "Create a form component with validation"
|
||||||
|
- "Add a useEffect to fetch user data"
|
||||||
|
- "Create a custom hook for local storage"
|
||||||
|
|
||||||
|
### TypeScript
|
||||||
|
- "Add proper TypeScript types to this component"
|
||||||
|
- "Create an interface for user data"
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- "Optimize this component with useMemo"
|
||||||
|
- "Add React.memo to prevent re-renders"
|
||||||
|
|
||||||
|
### Advanced
|
||||||
|
- "Create a Context provider for theme management"
|
||||||
|
- "Implement error boundary for this component"
|
||||||
|
- "Add lazy loading for this route"
|
||||||
|
|
||||||
|
## Comparing Results
|
||||||
|
|
||||||
|
Try the same prompt with and without `.cursorrules` to see the difference!
|
||||||
|
|
||||||
|
**Without .cursorrules**: Generic React code, may use outdated patterns
|
||||||
|
|
||||||
|
**With .cursorrules**: Modern React 18+, proper TypeScript, best practices
|
||||||
21
examples/cursor-react-skill/example-project/package.json
Normal file
21
examples/cursor-react-skill/example-project/package.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "cursor-react-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Example React project with Cursor AI rules",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.2.0",
|
||||||
|
"@types/react-dom": "^18.2.0",
|
||||||
|
"@vitejs/plugin-react": "^4.0.0",
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
"vite": "^4.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
examples/cursor-react-skill/example-project/src/App.tsx
Normal file
23
examples/cursor-react-skill/example-project/src/App.tsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
const [count, setCount] = useState(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
<h1>Cursor + React Example</h1>
|
||||||
|
<p>Count: {count}</p>
|
||||||
|
<button onClick={() => setCount(count + 1)}>
|
||||||
|
Increment
|
||||||
|
</button>
|
||||||
|
<button onClick={() => setCount(count - 1)}>
|
||||||
|
Decrement
|
||||||
|
</button>
|
||||||
|
<p>
|
||||||
|
Try using Cursor AI to generate more React components!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
||||||
13
examples/cursor-react-skill/example-project/src/index.tsx
Normal file
13
examples/cursor-react-skill/example-project/src/index.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
const root = ReactDOM.createRoot(
|
||||||
|
document.getElementById('root') as HTMLElement
|
||||||
|
);
|
||||||
|
|
||||||
|
root.render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
25
examples/cursor-react-skill/example-project/tsconfig.json
Normal file
25
examples/cursor-react-skill/example-project/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
||||||
143
examples/cursor-react-skill/generate_cursorrules.py
Normal file
143
examples/cursor-react-skill/generate_cursorrules.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Automate Cursor rules generation for React.
|
||||||
|
|
||||||
|
This script demonstrates the complete workflow:
|
||||||
|
1. Scrape React documentation
|
||||||
|
2. Package for Cursor
|
||||||
|
3. Extract and copy rules to project
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(cmd: list, description: str) -> bool:
|
||||||
|
"""Run a shell command and return success status."""
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"STEP: {description}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
print(f"Command: {' '.join(cmd)}\n")
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
print(f"❌ Error: {result.stderr}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"✅ Success!")
|
||||||
|
if result.stdout:
|
||||||
|
# Print first 500 chars to avoid clutter
|
||||||
|
output = result.stdout[:500]
|
||||||
|
if len(result.stdout) > 500:
|
||||||
|
output += "... (truncated)"
|
||||||
|
print(output)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run the automation workflow."""
|
||||||
|
print("=" * 60)
|
||||||
|
print("Cursor Rules Generator - React Example")
|
||||||
|
print("=" * 60)
|
||||||
|
print("\nThis script will:")
|
||||||
|
print(" 1. Scrape React documentation (100 pages)")
|
||||||
|
print(" 2. Package for Cursor IDE")
|
||||||
|
print(" 3. Extract and copy to example-project/")
|
||||||
|
print("\n⏱️ Estimated time: 2-3 minutes\n")
|
||||||
|
|
||||||
|
# Step 1: Scrape React docs
|
||||||
|
print("Starting workflow...")
|
||||||
|
if not run_command(
|
||||||
|
[
|
||||||
|
"skill-seekers",
|
||||||
|
"scrape",
|
||||||
|
"--config",
|
||||||
|
"../../configs/react.json",
|
||||||
|
"--max-pages",
|
||||||
|
"100",
|
||||||
|
],
|
||||||
|
"Scraping React documentation",
|
||||||
|
):
|
||||||
|
print("\n❌ Failed to scrape React documentation")
|
||||||
|
print(" Make sure skill-seekers is installed: pip install skill-seekers")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 2: Package for Cursor
|
||||||
|
if not run_command(
|
||||||
|
["skill-seekers", "package", "../../output/react", "--target", "claude"],
|
||||||
|
"Packaging for Cursor",
|
||||||
|
):
|
||||||
|
print("\n❌ Failed to package for Cursor")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 3: Extract ZIP
|
||||||
|
if not run_command(
|
||||||
|
[
|
||||||
|
"unzip",
|
||||||
|
"-o",
|
||||||
|
"../../output/react-claude.zip",
|
||||||
|
"-d",
|
||||||
|
"../../output/react-cursor",
|
||||||
|
],
|
||||||
|
"Extracting packaged skill",
|
||||||
|
):
|
||||||
|
print("\n❌ Failed to extract package")
|
||||||
|
print(" Make sure unzip is installed")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Step 4: Copy to example project
|
||||||
|
source = Path("../../output/react-cursor/SKILL.md")
|
||||||
|
target = Path("example-project/.cursorrules")
|
||||||
|
|
||||||
|
if not source.exists():
|
||||||
|
print(f"\n❌ Error: {source} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
target.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
target.write_text(source.read_text())
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"STEP: Copying rules to project")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
print(f"✅ Copied {source} → {target}")
|
||||||
|
|
||||||
|
# Success summary
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("✅ Cursor rules generated successfully!")
|
||||||
|
print("=" * 60)
|
||||||
|
print(f"\n📁 Rules file: {target.absolute()}")
|
||||||
|
print(f"📏 Size: {len(target.read_text())} characters")
|
||||||
|
|
||||||
|
# Preview first 300 characters
|
||||||
|
content = target.read_text()
|
||||||
|
preview = content[:300]
|
||||||
|
if len(content) > 300:
|
||||||
|
preview += "..."
|
||||||
|
|
||||||
|
print(f"\n📖 Preview:\n{preview}")
|
||||||
|
|
||||||
|
print("\n🚀 Next steps:")
|
||||||
|
print(" 1. Open example-project/ in Cursor:")
|
||||||
|
print(" cursor example-project/")
|
||||||
|
print("\n 2. Try these prompts:")
|
||||||
|
print(" - 'Create a useState hook for managing user data'")
|
||||||
|
print(" - 'Add useEffect to fetch data on mount'")
|
||||||
|
print(" - 'Implement a custom hook for form validation'")
|
||||||
|
print("\n 3. Compare AI suggestions with and without .cursorrules")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n\n⚠️ Interrupted by user")
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ Unexpected error: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
7
examples/cursor-react-skill/requirements.txt
Normal file
7
examples/cursor-react-skill/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Cursor React Skill Example Requirements
|
||||||
|
|
||||||
|
# Skill Seekers - documentation to AI skills converter
|
||||||
|
skill-seekers>=2.10.0
|
||||||
|
|
||||||
|
# No additional Python dependencies needed
|
||||||
|
# The example project uses Node.js/npm for React
|
||||||
Reference in New Issue
Block a user