✨ Add design-pattern-learner skill with auto-trigger
NEW SKILL: Design Pattern Learner - Studies and implements web design patterns from external sources - Fetches gists, repositories, and webpages - Analyzes design tokens (colors, typography, spacing, effects) - Extracts UI components (buttons, cards, modals, etc.) - Generates implementation code (Tailwind, React, Vue) Auto-Trigger Patterns: - "study design from [URL]" - "learn from [source]" - "implement this design" - "copy style from" - "extract component from" Integration: - Works alongside ui-ux-pro-max for design guidance - Uses codebase-indexer to find implementation locations - Uses mcp-client for external content fetching - Added to always-use-superpowers decision tree Updated Files: - skills/design-pattern-learner/skill.md - Complete skill documentation - skills/design-pattern-learner/scripts/analyze.py - Pattern analyzer - skills/design-pattern-learner/scripts/generate.py - Implementation generator - skills/design-pattern-learner/README.md - Quick start guide - ralph-integration/dispatch/auto-triggers.yml - Priority 7 - skills/always-use-superpowers/SKILL.md - Decision tree updated 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,14 @@ You MUST:
|
|||||||
- Use before: Any design work, HTML/CSS, component creation, layouts
|
- Use before: Any design work, HTML/CSS, component creation, layouts
|
||||||
- Priority: HIGH for any UI/UX work
|
- Priority: HIGH for any UI/UX work
|
||||||
|
|
||||||
#### 5. codebase-indexer (ALWAYS ACTIVE)
|
#### 5. design-pattern-learner
|
||||||
|
**When to use:** Studying or implementing designs from external sources
|
||||||
|
- Use before: Learning from gists, repositories, or external websites
|
||||||
|
- Triggers on: "study design from", "learn from", "implement this design", "copy style from"
|
||||||
|
- Priority: HIGH for external design learning
|
||||||
|
- Benefit: Fetches, analyzes, and implements patterns from any design source
|
||||||
|
|
||||||
|
#### 6. codebase-indexer (ALWAYS ACTIVE)
|
||||||
**When to use:** EVERY TASK involving code navigation, file searches, codebase understanding
|
**When to use:** EVERY TASK involving code navigation, file searches, codebase understanding
|
||||||
- **ALWAYS RUN THIS FIRST** before any code-related task
|
- **ALWAYS RUN THIS FIRST** before any code-related task
|
||||||
- Use for: Finding files, understanding code structure, semantic search, 40-60% token reduction
|
- Use for: Finding files, understanding code structure, semantic search, 40-60% token reduction
|
||||||
@@ -79,6 +86,9 @@ User sends message
|
|||||||
Check: Is this code-related work?
|
Check: Is this code-related work?
|
||||||
↓ YES → Invoke codebase-indexer (ALWAYS)
|
↓ YES → Invoke codebase-indexer (ALWAYS)
|
||||||
↓ NO
|
↓ NO
|
||||||
|
Check: Is this studying/learning external design?
|
||||||
|
↓ YES → Invoke design-pattern-learner
|
||||||
|
↓ NO
|
||||||
Check: Is this UI/UX work?
|
Check: Is this UI/UX work?
|
||||||
↓ YES → Invoke ui-ux-pro-max
|
↓ YES → Invoke ui-ux-pro-max
|
||||||
↓ NO
|
↓ NO
|
||||||
|
|||||||
35
skills/design-pattern-learner/README.md
Normal file
35
skills/design-pattern-learner/README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Design Pattern Learner Skill
|
||||||
|
|
||||||
|
**Auto-triggers when user wants to study/learn from external design sources**
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Analyze a design source
|
||||||
|
python3 scripts/analyze.py "https://gist.github.com/user/id"
|
||||||
|
|
||||||
|
# Generate implementation
|
||||||
|
python3 scripts/generate.py --source ~/.claude/skills/design-pattern-learner/data/patterns/[file] --framework tailwind
|
||||||
|
```
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
1. **Fetches** designs from gists, repos, or webpages
|
||||||
|
2. **Analyzes** design tokens (colors, typography, spacing, effects)
|
||||||
|
3. **Extracts** components (buttons, cards, modals, etc.)
|
||||||
|
4. **Generates** implementation code (Tailwind, React, Vue)
|
||||||
|
|
||||||
|
## Auto-Trigger Patterns
|
||||||
|
|
||||||
|
- "study design from [URL]"
|
||||||
|
- "learn from [source]"
|
||||||
|
- "implement this design"
|
||||||
|
- "copy style from"
|
||||||
|
- "replicate this pattern"
|
||||||
|
|
||||||
|
## Integration
|
||||||
|
|
||||||
|
Works alongside:
|
||||||
|
- `ui-ux-pro-max` - Design guidance
|
||||||
|
- `codebase-indexer` - Find files
|
||||||
|
- `always-use-superpowers` - Auto-dispatch
|
||||||
453
skills/design-pattern-learner/scripts/analyze.py
Executable file
453
skills/design-pattern-learner/scripts/analyze.py
Executable file
@@ -0,0 +1,453 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Design Pattern Analyzer
|
||||||
|
Fetches and analyzes design patterns from external sources
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from datetime import datetime
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
class DesignPatternAnalyzer:
|
||||||
|
def __init__(self, source_url):
|
||||||
|
self.source_url = source_url
|
||||||
|
self.patterns = {
|
||||||
|
"source": source_url,
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"design_tokens": {},
|
||||||
|
"components": [],
|
||||||
|
"layouts": [],
|
||||||
|
"animations": []
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetch_source(self):
|
||||||
|
"""Fetch content from URL/gist/repo"""
|
||||||
|
print(f"📥 Fetching source: {self.source_url}")
|
||||||
|
|
||||||
|
# Detect source type
|
||||||
|
if "gist.github.com" in self.source_url:
|
||||||
|
return self._fetch_gist()
|
||||||
|
elif "github.com" in self.source_url:
|
||||||
|
return self._fetch_github_repo()
|
||||||
|
else:
|
||||||
|
return self._fetch_webpage()
|
||||||
|
|
||||||
|
def _fetch_gist(self):
|
||||||
|
"""Fetch gist content using git"""
|
||||||
|
print("🔍 Detected: GitHub Gist")
|
||||||
|
|
||||||
|
# Extract gist ID
|
||||||
|
gist_match = re.search(r'gist\.github\.com/[^/]+/([a-f0-9]+)', self.source_url)
|
||||||
|
if not gist_match:
|
||||||
|
gist_match = re.search(r'gist\.github\.com/([a-f0-9]+)', self.source_url)
|
||||||
|
|
||||||
|
if gist_match:
|
||||||
|
gist_id = gist_match.group(1)
|
||||||
|
gist_url = f"https://gist.github.com/{gist_id}"
|
||||||
|
|
||||||
|
# Use curl to fetch
|
||||||
|
result = subprocess.run(
|
||||||
|
['curl', '-s', gist_url],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
return self._parse_gist_html(result.stdout)
|
||||||
|
else:
|
||||||
|
print(f"❌ Failed to fetch gist: {result.stderr}")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
print("❌ Could not extract gist ID")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_github_repo(self):
|
||||||
|
"""Fetch GitHub repository"""
|
||||||
|
print("🔍 Detected: GitHub Repository")
|
||||||
|
print("⚠️ Repo analysis requires cloning - will analyze README and structure")
|
||||||
|
|
||||||
|
# For now, analyze the main page
|
||||||
|
result = subprocess.run(
|
||||||
|
['curl', '-s', self.source_url],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
return self._parse_github_page(result.stdout)
|
||||||
|
else:
|
||||||
|
print(f"❌ Failed to fetch repo: {result.stderr}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _fetch_webpage(self):
|
||||||
|
"""Fetch regular webpage"""
|
||||||
|
print("🔍 Detected: Webpage")
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
['curl', '-s', '-L', self.source_url],
|
||||||
|
capture_output=True,
|
||||||
|
text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode == 0:
|
||||||
|
return result.stdout
|
||||||
|
else:
|
||||||
|
print(f"❌ Failed to fetch webpage: {result.stderr}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _parse_gist_html(self, html):
|
||||||
|
"""Parse gist HTML to extract code"""
|
||||||
|
print("📄 Parsing gist content...")
|
||||||
|
|
||||||
|
# Look for file content in gist HTML
|
||||||
|
# Extract from <div class="highlight"> or similar
|
||||||
|
file_pattern = r'<div class="[^"]*highlight[^"]*"[^>]*>(.*?)</div>'
|
||||||
|
files = re.findall(file_pattern, html, re.DOTALL)
|
||||||
|
|
||||||
|
if files:
|
||||||
|
# Clean up HTML entities and tags
|
||||||
|
content = []
|
||||||
|
for file_html in files:
|
||||||
|
# Remove HTML tags but keep code
|
||||||
|
clean_code = re.sub(r'<[^>]+>', '\n', file_html)
|
||||||
|
clean_code = re.sub(r'<', '<', clean_code)
|
||||||
|
clean_code = re.sub(r'>', '>', clean_code)
|
||||||
|
clean_code = re.sub(r'&', '&', clean_code)
|
||||||
|
clean_code = re.sub(r'\n\s*\n', '\n', clean_code)
|
||||||
|
content.append(clean_code.strip())
|
||||||
|
|
||||||
|
return '\n\n'.join(content)
|
||||||
|
else:
|
||||||
|
print("⚠️ Could not extract gist files")
|
||||||
|
return html
|
||||||
|
|
||||||
|
def _parse_github_page(self, html):
|
||||||
|
"""Parse GitHub repo page"""
|
||||||
|
print("📄 Parsing repository page...")
|
||||||
|
return html
|
||||||
|
|
||||||
|
def analyze_design_tokens(self, content):
|
||||||
|
"""Extract design tokens from content"""
|
||||||
|
print("\n🎨 Extracting Design Tokens...")
|
||||||
|
|
||||||
|
tokens = {}
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
colors = self._extract_colors(content)
|
||||||
|
if colors:
|
||||||
|
tokens['colors'] = colors
|
||||||
|
print(f" ✓ Found {len(colors)} color patterns")
|
||||||
|
|
||||||
|
# Typography
|
||||||
|
typography = self._extract_typography(content)
|
||||||
|
if typography:
|
||||||
|
tokens['typography'] = typography
|
||||||
|
print(f" ✓ Found {len(typography.get('fonts', []))} font patterns")
|
||||||
|
|
||||||
|
# Spacing
|
||||||
|
spacing = self._extract_spacing(content)
|
||||||
|
if spacing:
|
||||||
|
tokens['spacing'] = spacing
|
||||||
|
print(f" ✓ Found spacing patterns")
|
||||||
|
|
||||||
|
# Effects
|
||||||
|
effects = self._extract_effects(content)
|
||||||
|
if effects:
|
||||||
|
tokens['effects'] = effects
|
||||||
|
print(f" ✓ Found {len(effects.get('shadows', []))} shadow patterns")
|
||||||
|
|
||||||
|
self.patterns['design_tokens'] = tokens
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def _extract_colors(self, content):
|
||||||
|
"""Extract color patterns"""
|
||||||
|
colors = {}
|
||||||
|
|
||||||
|
# Hex colors
|
||||||
|
hex_colors = re.findall(r'#[0-9a-fA-F]{3,6}', content)
|
||||||
|
if hex_colors:
|
||||||
|
colors['hex'] = list(set(hex_colors))[:20] # Limit to 20 unique
|
||||||
|
|
||||||
|
# Tailwind color classes
|
||||||
|
tailwind_colors = re.findall(r'\b(bg|text|border)-([a-z]+)-(\d+)\b', content)
|
||||||
|
if tailwind_colors:
|
||||||
|
colors['tailwind'] = [
|
||||||
|
f"{prefix}-{color}-{shade}"
|
||||||
|
for prefix, color, shade in tailwind_colors
|
||||||
|
][:20]
|
||||||
|
|
||||||
|
# CSS color names
|
||||||
|
css_colors = re.findall(r'\b(black|white|gray|red|blue|green|yellow|purple|pink|indigo)\b', content, re.I)
|
||||||
|
if css_colors:
|
||||||
|
colors['css'] = list(set(css_colors))
|
||||||
|
|
||||||
|
return colors if colors else None
|
||||||
|
|
||||||
|
def _extract_typography(self, content):
|
||||||
|
"""Extract typography patterns"""
|
||||||
|
typo = {}
|
||||||
|
|
||||||
|
# Font families
|
||||||
|
fonts = re.findall(r'font-family:\s*([^;]+)', content, re.I)
|
||||||
|
if fonts:
|
||||||
|
typo['fonts'] = list(set(fonts))
|
||||||
|
|
||||||
|
# Font sizes
|
||||||
|
sizes = re.findall(r'(text-|font-)?size:\s*([^;]+)', content, re.I)
|
||||||
|
if sizes:
|
||||||
|
typo['sizes'] = list(set([s[1] for s in sizes]))
|
||||||
|
|
||||||
|
# Tailwind text classes
|
||||||
|
tailwind_text = re.findall(r'\b(text|font)-(xl|lg|md|sm|xs|\d)\b', content)
|
||||||
|
if tailwind_text:
|
||||||
|
typo['tailwind'] = [f"{prefix}-{size}" for prefix, size in tailwind_text]
|
||||||
|
|
||||||
|
return typo if typo else None
|
||||||
|
|
||||||
|
def _extract_spacing(self, content):
|
||||||
|
"""Extract spacing patterns"""
|
||||||
|
spacing = {}
|
||||||
|
|
||||||
|
# Tailwind spacing
|
||||||
|
tailwind_spacing = re.findall(r'\b(p|m|px|py|pt|pb|pl|pr)-(\\d+)\b', content)
|
||||||
|
if tailwind_spacing:
|
||||||
|
spacing['tailwind'] = list(set([f"{prefix}-{size}" for prefix, size in tailwind_spacing]))
|
||||||
|
|
||||||
|
# CSS spacing
|
||||||
|
css_spacing = re.findall(r'(padding|margin):\s*([^;]+)', content, re.I)
|
||||||
|
if css_spacing:
|
||||||
|
spacing['css'] = list(set([f"{prop}: {val}" for prop, val in css_spacing]))
|
||||||
|
|
||||||
|
return spacing if spacing else None
|
||||||
|
|
||||||
|
def _extract_effects(self, content):
|
||||||
|
"""Extract visual effects"""
|
||||||
|
effects = {}
|
||||||
|
|
||||||
|
# Shadows
|
||||||
|
shadows = re.findall(r'box-shadow:\s*([^;]+)', content, re.I)
|
||||||
|
if shadows:
|
||||||
|
effects['shadows'] = list(set(shadows))
|
||||||
|
|
||||||
|
# Tailwind shadows
|
||||||
|
tailwind_shadows = re.findall(r'\bshadow-(xl|lg|md|sm|none)\b', content)
|
||||||
|
if tailwind_shadows:
|
||||||
|
effects['tailwind_shadows'] = [f"shadow-{s}" for s in tailwind_shadows]
|
||||||
|
|
||||||
|
# Border radius
|
||||||
|
radius = re.findall(r'border-radius:\s*([^;]+)', content, re.I)
|
||||||
|
if radius:
|
||||||
|
effects['radius'] = list(set(radius))
|
||||||
|
|
||||||
|
return effects if effects else None
|
||||||
|
|
||||||
|
def analyze_components(self, content):
|
||||||
|
"""Extract UI components"""
|
||||||
|
print("\n🧩 Identifying Components...")
|
||||||
|
|
||||||
|
components = []
|
||||||
|
|
||||||
|
# Look for common component patterns
|
||||||
|
component_patterns = {
|
||||||
|
'button': r'<button[^>]*>.*?</button>|class="[^"]*button[^"]*"',
|
||||||
|
'card': r'class="[^"]*card[^"]*"',
|
||||||
|
'modal': r'class="[^"]*modal[^"]*"',
|
||||||
|
'nav': r'<nav[^>]*>.*?</nav>|class="[^"]*nav[^"]*"',
|
||||||
|
'form': r'<form[^>]*>.*?</form>|class="[^"]*form[^"]*"',
|
||||||
|
'input': r'<input[^>]*/?>|class="[^"]*input[^"]*"',
|
||||||
|
'hero': r'class="[^"]*hero[^"]*"',
|
||||||
|
'footer': r'<footer[^>]*>.*?</footer>',
|
||||||
|
'header': r'<header[^>]*>.*?</header>',
|
||||||
|
}
|
||||||
|
|
||||||
|
for comp_name, pattern in component_patterns.items():
|
||||||
|
matches = re.findall(pattern, content, re.DOTALL | re.IGNORECASE)
|
||||||
|
if matches:
|
||||||
|
components.append({
|
||||||
|
'type': comp_name,
|
||||||
|
'count': len(matches),
|
||||||
|
'examples': matches[:3] # First 3 examples
|
||||||
|
})
|
||||||
|
print(f" ✓ Found {len(matches)} {comp_name} component(s)")
|
||||||
|
|
||||||
|
self.patterns['components'] = components
|
||||||
|
return components
|
||||||
|
|
||||||
|
def analyze_layouts(self, content):
|
||||||
|
"""Extract layout patterns"""
|
||||||
|
print("\n📐 Analyzing Layouts...")
|
||||||
|
|
||||||
|
layouts = []
|
||||||
|
|
||||||
|
# Grid layouts
|
||||||
|
grids = re.findall(r'grid-cols-\\d+', content)
|
||||||
|
if grids:
|
||||||
|
layouts.append({
|
||||||
|
'type': 'grid',
|
||||||
|
'variants': list(set(grids))
|
||||||
|
})
|
||||||
|
print(f" ✓ Found grid layouts: {list(set(grids))}")
|
||||||
|
|
||||||
|
# Flexbox
|
||||||
|
flex_patterns = re.findall(r'flex-(row|col|wrap|nowrap)', content)
|
||||||
|
if flex_patterns:
|
||||||
|
layouts.append({
|
||||||
|
'type': 'flexbox',
|
||||||
|
'patterns': list(set(flex_patterns))
|
||||||
|
})
|
||||||
|
print(f" ✓ Found flexbox patterns: {list(set(flex_patterns))}")
|
||||||
|
|
||||||
|
# Containers
|
||||||
|
containers = re.findall(r'class="[^"]*container[^"]*"', content)
|
||||||
|
if containers:
|
||||||
|
layouts.append({
|
||||||
|
'type': 'container',
|
||||||
|
'count': len(containers)
|
||||||
|
})
|
||||||
|
print(f" ✓ Found {len(containers)} container(s)")
|
||||||
|
|
||||||
|
self.patterns['layouts'] = layouts
|
||||||
|
return layouts
|
||||||
|
|
||||||
|
def analyze_animations(self, content):
|
||||||
|
"""Extract animation patterns"""
|
||||||
|
print("\n✨ Analyzing Animations...")
|
||||||
|
|
||||||
|
animations = []
|
||||||
|
|
||||||
|
# Transitions
|
||||||
|
transitions = re.findall(r'transition(?:-[^:]*)?:\\s*([^;]+)', content, re.I)
|
||||||
|
if transitions:
|
||||||
|
animations.append({
|
||||||
|
'type': 'transition',
|
||||||
|
'patterns': list(set(transitions))[:10]
|
||||||
|
})
|
||||||
|
print(f" ✓ Found transitions: {len(set(transitions))}")
|
||||||
|
|
||||||
|
# Transforms
|
||||||
|
transforms = re.findall(r'transform:\\s*([^;]+)', content, re.I)
|
||||||
|
if transforms:
|
||||||
|
animations.append({
|
||||||
|
'type': 'transform',
|
||||||
|
'patterns': list(set(transforms))
|
||||||
|
})
|
||||||
|
print(f" ✓ Found transforms: {len(set(transforms))}")
|
||||||
|
|
||||||
|
# Keyframes
|
||||||
|
keyframes = re.findall(r'@keyframes\\s+(\\w+)', content)
|
||||||
|
if keyframes:
|
||||||
|
animations.append({
|
||||||
|
'type': 'keyframe',
|
||||||
|
'names': list(set(keyframes))
|
||||||
|
})
|
||||||
|
print(f" ✓ Found keyframes: {list(set(keyframes))}")
|
||||||
|
|
||||||
|
self.patterns['animations'] = animations
|
||||||
|
return animations
|
||||||
|
|
||||||
|
def save_patterns(self):
|
||||||
|
"""Save extracted patterns to file"""
|
||||||
|
# Create data directory if needed
|
||||||
|
data_dir = os.path.expanduser('~/.claude/skills/design-pattern-learner/data/patterns')
|
||||||
|
os.makedirs(data_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Generate filename from URL
|
||||||
|
safe_name = re.sub(r'[^a-zA-Z0-9]', '_', self.source_url)[:50]
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
filename = f"{safe_name}_{timestamp}.json"
|
||||||
|
filepath = os.path.join(data_dir, filename)
|
||||||
|
|
||||||
|
# Save patterns
|
||||||
|
with open(filepath, 'w') as f:
|
||||||
|
json.dump(self.patterns, f, indent=2)
|
||||||
|
|
||||||
|
print(f"\n💾 Patterns saved to: {filepath}")
|
||||||
|
|
||||||
|
# Also save to learning history
|
||||||
|
history_file = os.path.expanduser('~/.claude/skills/design-pattern-learner/learning-history.jsonl')
|
||||||
|
with open(history_file, 'a') as f:
|
||||||
|
f.write(json.dumps({
|
||||||
|
'timestamp': datetime.now().isoformat(),
|
||||||
|
'source': self.source_url,
|
||||||
|
'file': filename,
|
||||||
|
'patterns_count': len(self.patterns['components']),
|
||||||
|
'success': True
|
||||||
|
}) + '\n')
|
||||||
|
|
||||||
|
return filepath
|
||||||
|
|
||||||
|
def generate_summary(self):
|
||||||
|
"""Generate human-readable summary"""
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("📊 DESIGN PATTERN ANALYSIS SUMMARY")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
print(f"\n📍 Source: {self.source_url}")
|
||||||
|
print(f"🕐 Analyzed: {self.patterns['timestamp']}")
|
||||||
|
|
||||||
|
# Design tokens
|
||||||
|
if self.patterns['design_tokens']:
|
||||||
|
print("\n🎨 Design Tokens:")
|
||||||
|
for category, values in self.patterns['design_tokens'].items():
|
||||||
|
print(f" • {category}: {len(values)} patterns")
|
||||||
|
|
||||||
|
# Components
|
||||||
|
if self.patterns['components']:
|
||||||
|
print(f"\n🧩 Components Found: {len(self.patterns['components'])}")
|
||||||
|
for comp in self.patterns['components']:
|
||||||
|
print(f" • {comp['type']}: {comp['count']} instance(s)")
|
||||||
|
|
||||||
|
# Layouts
|
||||||
|
if self.patterns['layouts']:
|
||||||
|
print(f"\n📐 Layout Patterns: {len(self.patterns['layouts'])}")
|
||||||
|
for layout in self.patterns['layouts']:
|
||||||
|
print(f" • {layout['type']}")
|
||||||
|
|
||||||
|
# Animations
|
||||||
|
if self.patterns['animations']:
|
||||||
|
print(f"\n✨ Animations: {len(self.patterns['animations'])}")
|
||||||
|
for anim in self.patterns['animations']:
|
||||||
|
print(f" • {anim['type']}")
|
||||||
|
|
||||||
|
print("\n" + "="*60)
|
||||||
|
print("✅ Analysis Complete!")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: python3 analyze.py <URL>")
|
||||||
|
print("Example: python3 analyze.py https://gist.github.com/user/id")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
url = sys.argv[1]
|
||||||
|
|
||||||
|
analyzer = DesignPatternAnalyzer(url)
|
||||||
|
|
||||||
|
# Fetch content
|
||||||
|
content = analyzer.fetch_source()
|
||||||
|
if not content:
|
||||||
|
print("❌ Failed to fetch content")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Analyze patterns
|
||||||
|
analyzer.analyze_design_tokens(content)
|
||||||
|
analyzer.analyze_components(content)
|
||||||
|
analyzer.analyze_layouts(content)
|
||||||
|
analyzer.analyze_animations(content)
|
||||||
|
|
||||||
|
# Save results
|
||||||
|
filepath = analyzer.save_patterns()
|
||||||
|
|
||||||
|
# Show summary
|
||||||
|
analyzer.generate_summary()
|
||||||
|
|
||||||
|
print(f"\n💡 Next steps:")
|
||||||
|
print(f" • View patterns: cat {filepath}")
|
||||||
|
print(f" • Generate implementation: python3 generate.py --source {filepath}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
502
skills/design-pattern-learner/scripts/generate.py
Executable file
502
skills/design-pattern-learner/scripts/generate.py
Executable file
@@ -0,0 +1,502 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Pattern Implementation Generator
|
||||||
|
Generates implementation code from analyzed patterns
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class PatternGenerator:
|
||||||
|
def __init__(self, pattern_file, framework='tailwind'):
|
||||||
|
self.pattern_file = pattern_file
|
||||||
|
self.framework = framework
|
||||||
|
self.patterns = None
|
||||||
|
|
||||||
|
def load_patterns(self):
|
||||||
|
"""Load pattern JSON file"""
|
||||||
|
print(f"📖 Loading patterns from: {self.pattern_file}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self.pattern_file, 'r') as f:
|
||||||
|
self.patterns = json.load(f)
|
||||||
|
print(f"✅ Patterns loaded successfully")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error loading patterns: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def generate_component_library(self):
|
||||||
|
"""Generate component library from patterns"""
|
||||||
|
print(f"\n🧩 Generating Component Library for {self.framework}...")
|
||||||
|
|
||||||
|
if not self.patterns.get('components'):
|
||||||
|
print("⚠️ No components found in patterns")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
library = {}
|
||||||
|
|
||||||
|
for comp in self.patterns['components']:
|
||||||
|
comp_type = comp['type']
|
||||||
|
examples = comp.get('examples', [])
|
||||||
|
|
||||||
|
if not examples:
|
||||||
|
continue
|
||||||
|
|
||||||
|
library[comp_type] = {
|
||||||
|
'count': comp['count'],
|
||||||
|
'implementations': []
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, example in enumerate(examples[:2]): # Max 2 examples
|
||||||
|
impl = self._convert_to_framework(comp_type, example)
|
||||||
|
if impl:
|
||||||
|
library[comp_type]['implementations'].append(impl)
|
||||||
|
|
||||||
|
print(f" ✓ Generated {comp_type} component")
|
||||||
|
|
||||||
|
return library
|
||||||
|
|
||||||
|
def _convert_to_framework(self, comp_type, html_snippet):
|
||||||
|
"""Convert HTML snippet to target framework"""
|
||||||
|
|
||||||
|
# Clean up the snippet
|
||||||
|
snippet = html_snippet.strip()
|
||||||
|
|
||||||
|
if self.framework == 'tailwind':
|
||||||
|
return self._convert_tailwind(comp_type, snippet)
|
||||||
|
elif self.framework == 'react':
|
||||||
|
return self._convert_react(comp_type, snippet)
|
||||||
|
elif self.framework == 'vue':
|
||||||
|
return self._convert_vue(comp_type, snippet)
|
||||||
|
else:
|
||||||
|
return {'html': snippet}
|
||||||
|
|
||||||
|
def _convert_tailwind(self, comp_type, snippet):
|
||||||
|
"""Convert to Tailwind HTML"""
|
||||||
|
# Extract classes if present
|
||||||
|
import re
|
||||||
|
|
||||||
|
classes = re.findall(r'class="([^"]*)"', snippet)
|
||||||
|
all_classes = ' '.join(classes) if classes else ''
|
||||||
|
|
||||||
|
return {
|
||||||
|
'framework': 'tailwind',
|
||||||
|
'html': snippet,
|
||||||
|
'classes': all_classes,
|
||||||
|
'usage': f'<!-- Copy this HTML for your {comp_type} -->'
|
||||||
|
}
|
||||||
|
|
||||||
|
def _convert_react(self, comp_type, snippet):
|
||||||
|
"""Convert to React component"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
# Extract classes
|
||||||
|
classes = re.findall(r'class="([^"]*)"', snippet)
|
||||||
|
|
||||||
|
# Convert to JSX
|
||||||
|
jsx = snippet
|
||||||
|
# Replace class with className
|
||||||
|
jsx = re.sub(r'class=', 'className=', jsx)
|
||||||
|
# Close self-closing tags
|
||||||
|
jsx = re.sub(r'<input([^>]*)>', r'<input\1 />', jsx)
|
||||||
|
|
||||||
|
component_name = ''.join([w.capitalize() for w in comp_type.split('_')])
|
||||||
|
|
||||||
|
return {
|
||||||
|
'framework': 'react',
|
||||||
|
'component_name': component_name,
|
||||||
|
'jsx': jsx,
|
||||||
|
'code': f'''export function {component_name}() {{
|
||||||
|
return (
|
||||||
|
{self._indent_jsx(jsx, 4)}
|
||||||
|
);
|
||||||
|
}}'''
|
||||||
|
}
|
||||||
|
|
||||||
|
def _convert_vue(self, comp_type, snippet):
|
||||||
|
"""Convert to Vue component"""
|
||||||
|
component_name = ''.join([w.capitalize() for w in comp_type.split('_')])
|
||||||
|
|
||||||
|
return {
|
||||||
|
'framework': 'vue',
|
||||||
|
'component_name': component_name,
|
||||||
|
'template': snippet,
|
||||||
|
'code': f'''<template>
|
||||||
|
{self._indent_jsx(snippet, 2)}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
// {component_name} component
|
||||||
|
</script>'''
|
||||||
|
}
|
||||||
|
|
||||||
|
def _indent_jsx(self, code, spaces):
|
||||||
|
"""Indent multi-line JSX/Vue code"""
|
||||||
|
lines = code.split('\n')
|
||||||
|
indent = ' ' * spaces
|
||||||
|
return '\n'.join([indent + line if line.strip() else line for line in lines])
|
||||||
|
|
||||||
|
def generate_design_system(self):
|
||||||
|
"""Generate design system from tokens"""
|
||||||
|
print(f"\n🎨 Generating Design System...")
|
||||||
|
|
||||||
|
if not self.patterns.get('design_tokens'):
|
||||||
|
print("⚠️ No design tokens found")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
tokens = self.patterns['design_tokens']
|
||||||
|
design_system = {}
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
if 'colors' in tokens:
|
||||||
|
design_system['colors'] = self._generate_color_tokens(tokens['colors'])
|
||||||
|
|
||||||
|
# Typography
|
||||||
|
if 'typography' in tokens:
|
||||||
|
design_system['typography'] = self._generate_typography_tokens(tokens['typography'])
|
||||||
|
|
||||||
|
# Spacing
|
||||||
|
if 'spacing' in tokens:
|
||||||
|
design_system['spacing'] = self._generate_spacing_tokens(tokens['spacing'])
|
||||||
|
|
||||||
|
# Effects
|
||||||
|
if 'effects' in tokens:
|
||||||
|
design_system['effects'] = self._generate_effect_tokens(tokens['effects'])
|
||||||
|
|
||||||
|
return design_system
|
||||||
|
|
||||||
|
def _generate_color_tokens(self, colors):
|
||||||
|
"""Generate color tokens"""
|
||||||
|
tokens = {'tailwind': {}, 'hex': {}}
|
||||||
|
|
||||||
|
if 'tailwind' in colors:
|
||||||
|
# Group by color name
|
||||||
|
for color_class in colors['tailwind']:
|
||||||
|
parts = color_class.split('-')
|
||||||
|
if len(parts) >= 3:
|
||||||
|
prop, color, shade = parts[0], parts[1], parts[2]
|
||||||
|
if color not in tokens['tailwind']:
|
||||||
|
tokens['tailwind'][color] = []
|
||||||
|
tokens['tailwind'][color].append(shade)
|
||||||
|
|
||||||
|
if 'hex' in colors:
|
||||||
|
tokens['hex'] = colors['hex'][:10] # Limit to 10
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def _generate_typography_tokens(self, typography):
|
||||||
|
"""Generate typography tokens"""
|
||||||
|
tokens = {}
|
||||||
|
|
||||||
|
if 'fonts' in typography:
|
||||||
|
tokens['font_families'] = typography['fonts']
|
||||||
|
|
||||||
|
if 'sizes' in typography:
|
||||||
|
tokens['font_sizes'] = typography['sizes']
|
||||||
|
|
||||||
|
if 'tailwind' in typography:
|
||||||
|
tokens['tailwind_classes'] = typography['tailwind']
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def _generate_spacing_tokens(self, spacing):
|
||||||
|
"""Generate spacing tokens"""
|
||||||
|
tokens = {}
|
||||||
|
|
||||||
|
if 'tailwind' in spacing:
|
||||||
|
# Extract unique spacing values
|
||||||
|
values = set()
|
||||||
|
for class_name in spacing['tailwind']:
|
||||||
|
parts = class_name.split('-')
|
||||||
|
if len(parts) >= 2:
|
||||||
|
values.add(parts[-1])
|
||||||
|
tokens['tailwind_scale'] = list(values)
|
||||||
|
|
||||||
|
if 'css' in spacing:
|
||||||
|
tokens['css_values'] = spacing['css'][:5]
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def _generate_effect_tokens(self, effects):
|
||||||
|
"""Generate effect tokens"""
|
||||||
|
tokens = {}
|
||||||
|
|
||||||
|
if 'shadows' in effects:
|
||||||
|
tokens['box_shadows'] = effects['shadows'][:5]
|
||||||
|
|
||||||
|
if 'tailwind_shadows' in effects:
|
||||||
|
tokens['tailwind_shadows'] = effects['tailwind_shadows']
|
||||||
|
|
||||||
|
if 'radius' in effects:
|
||||||
|
tokens['border_radius'] = effects['radius']
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
def generate_implementation_guide(self):
|
||||||
|
"""Generate implementation guide"""
|
||||||
|
print(f"\n📖 Generating Implementation Guide...")
|
||||||
|
|
||||||
|
source = self.patterns.get('source', 'Unknown')
|
||||||
|
timestamp = self.patterns.get('timestamp', datetime.now().isoformat())
|
||||||
|
|
||||||
|
guide = f'''# Design Pattern Implementation Guide
|
||||||
|
|
||||||
|
**Source:** {source}
|
||||||
|
**Analyzed:** {timestamp}
|
||||||
|
**Framework:** {self.framework}
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
1. Review the design tokens below
|
||||||
|
2. Copy component code for your needs
|
||||||
|
3. Integrate into your project
|
||||||
|
4. Customize as needed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Design System
|
||||||
|
|
||||||
|
### Colors
|
||||||
|
{self._format_colors()}
|
||||||
|
|
||||||
|
### Typography
|
||||||
|
{self._format_typography()}
|
||||||
|
|
||||||
|
### Spacing
|
||||||
|
{self._format_spacing()}
|
||||||
|
|
||||||
|
### Effects
|
||||||
|
{self._format_effects()}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
{self._format_components()}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Applying Design Tokens
|
||||||
|
|
||||||
|
```{self.framework}
|
||||||
|
<!-- Example with design tokens -->
|
||||||
|
<div class="bg-primary-500 text-white p-4 rounded-lg shadow-lg">
|
||||||
|
Content here
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Components
|
||||||
|
|
||||||
|
Copy any component from the Components section above and adapt to your needs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
### Modify Colors
|
||||||
|
Update your Tailwind config or CSS variables to match the design tokens.
|
||||||
|
|
||||||
|
### Adjust Spacing
|
||||||
|
Scale spacing values up or down based on your design system.
|
||||||
|
|
||||||
|
### Add Effects
|
||||||
|
Apply the shadow and radius patterns to other components.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This implementation is based on design patterns from: {source}
|
||||||
|
|
||||||
|
Please respect the original source's license and attribution requirements.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Generated by:** Design Pattern Learner v1.0
|
||||||
|
**Date:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||||
|
'''
|
||||||
|
|
||||||
|
return guide
|
||||||
|
|
||||||
|
def _format_colors(self):
|
||||||
|
"""Format colors for guide"""
|
||||||
|
if not self.patterns.get('design_tokens', {}).get('colors'):
|
||||||
|
return 'No color patterns found'
|
||||||
|
|
||||||
|
colors = self.patterns['design_tokens']['colors']
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if 'tailwind' in colors:
|
||||||
|
lines.append('\n**Tailwind Colors:**')
|
||||||
|
for color in list(colors['tailwind'])[:10]:
|
||||||
|
lines.append(f'- `{color}`')
|
||||||
|
|
||||||
|
if 'hex' in colors:
|
||||||
|
lines.append('\n**Hex Colors:**')
|
||||||
|
for hex_color in colors['hex'][:10]:
|
||||||
|
lines.append(f'- `{hex_color}`')
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def _format_typography(self):
|
||||||
|
"""Format typography for guide"""
|
||||||
|
if not self.patterns.get('design_tokens', {}).get('typography'):
|
||||||
|
return 'No typography patterns found'
|
||||||
|
|
||||||
|
typo = self.patterns['design_tokens']['typography']
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if 'fonts' in typo:
|
||||||
|
lines.append('\n**Font Families:**')
|
||||||
|
for font in typo['fonts'][:5]:
|
||||||
|
lines.append(f'- `{font}`')
|
||||||
|
|
||||||
|
if 'tailwind' in typo:
|
||||||
|
lines.append('\n**Tailwind Text Classes:**')
|
||||||
|
for cls in typo['tailwind'][:10]:
|
||||||
|
lines.append(f'- `{cls}`')
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def _format_spacing(self):
|
||||||
|
"""Format spacing for guide"""
|
||||||
|
if not self.patterns.get('design_tokens', {}).get('spacing'):
|
||||||
|
return 'No spacing patterns found'
|
||||||
|
|
||||||
|
spacing = self.patterns['design_tokens']['spacing']
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if 'tailwind' in spacing:
|
||||||
|
lines.append('\n**Tailwind Spacing:**')
|
||||||
|
for cls in list(spacing['tailwind'])[:10]:
|
||||||
|
lines.append(f'- `{cls}`')
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def _format_effects(self):
|
||||||
|
"""Format effects for guide"""
|
||||||
|
if not self.patterns.get('design_tokens', {}).get('effects'):
|
||||||
|
return 'No effect patterns found'
|
||||||
|
|
||||||
|
effects = self.patterns['design_tokens']['effects']
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if 'shadows' in effects:
|
||||||
|
lines.append('\n**Box Shadows:**')
|
||||||
|
for shadow in effects['shadows'][:5]:
|
||||||
|
lines.append(f'- `{shadow}`')
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def _format_components(self):
|
||||||
|
"""Format components for guide"""
|
||||||
|
if not self.patterns.get('components'):
|
||||||
|
return 'No components found'
|
||||||
|
|
||||||
|
library = self.generate_component_library()
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
for comp_name, comp_data in library.items():
|
||||||
|
lines.append(f'\n### {comp_name.capitalize()}')
|
||||||
|
lines.append(f'\nFound: {comp_data["count"]} instance(s)')
|
||||||
|
|
||||||
|
for impl in comp_data.get('implementations', [])[:2]:
|
||||||
|
if self.framework == 'tailwind':
|
||||||
|
lines.append(f'\n```html')
|
||||||
|
lines.append(impl.get('html', ''))
|
||||||
|
lines.append('```')
|
||||||
|
elif self.framework == 'react':
|
||||||
|
lines.append(f'\n```jsx')
|
||||||
|
lines.append(impl.get('code', ''))
|
||||||
|
lines.append('```')
|
||||||
|
elif self.framework == 'vue':
|
||||||
|
lines.append(f'\n```vue')
|
||||||
|
lines.append(impl.get('code', ''))
|
||||||
|
lines.append('```')
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
def save_outputs(self, library, design_system, guide):
|
||||||
|
"""Save generated outputs"""
|
||||||
|
output_dir = os.path.expanduser('~/.claude/skills/design-pattern-learner/data/outputs')
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
|
||||||
|
# Save component library
|
||||||
|
library_file = os.path.join(output_dir, f'library_{self.framework}_{timestamp}.json')
|
||||||
|
with open(library_file, 'w') as f:
|
||||||
|
json.dump(library, f, indent=2)
|
||||||
|
print(f'\n💾 Component library: {library_file}')
|
||||||
|
|
||||||
|
# Save design system
|
||||||
|
system_file = os.path.join(output_dir, f'design-system_{self.framework}_{timestamp}.json')
|
||||||
|
with open(system_file, 'w') as f:
|
||||||
|
json.dump(design_system, f, indent=2)
|
||||||
|
print(f'💾 Design system: {system_file}')
|
||||||
|
|
||||||
|
# Save implementation guide
|
||||||
|
guide_file = os.path.join(output_dir, f'implementation-guide_{self.framework}_{timestamp}.md')
|
||||||
|
with open(guide_file, 'w') as f:
|
||||||
|
f.write(guide)
|
||||||
|
print(f'💾 Implementation guide: {guide_file}')
|
||||||
|
|
||||||
|
return library_file, system_file, guide_file
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print("Usage: python3 generate.py --source <pattern_file> --framework <tailwind|react|vue>")
|
||||||
|
print("Example: python3 generate.py --source patterns.json --framework tailwind")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
pattern_file = None
|
||||||
|
framework = 'tailwind'
|
||||||
|
|
||||||
|
args = sys.argv[1:]
|
||||||
|
i = 0
|
||||||
|
while i < len(args):
|
||||||
|
if args[i] == '--source' and i + 1 < len(args):
|
||||||
|
pattern_file = args[i + 1]
|
||||||
|
i += 2
|
||||||
|
elif args[i] == '--framework' and i + 1 < len(args):
|
||||||
|
framework = args[i + 1].lower()
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
if not pattern_file:
|
||||||
|
print("❌ Error: --source parameter is required")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if framework not in ['tailwind', 'react', 'vue']:
|
||||||
|
print(f"⚠️ Warning: Unknown framework '{framework}', using 'tailwind'")
|
||||||
|
framework = 'tailwind'
|
||||||
|
|
||||||
|
generator = PatternGenerator(pattern_file, framework)
|
||||||
|
|
||||||
|
if not generator.load_patterns():
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"🚀 GENERATING IMPLEMENTATION FOR {framework.upper()}")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
# Generate outputs
|
||||||
|
library = generator.generate_component_library()
|
||||||
|
design_system = generator.generate_design_system()
|
||||||
|
guide = generator.generate_implementation_guide()
|
||||||
|
|
||||||
|
# Save outputs
|
||||||
|
generator.save_outputs(library, design_system, guide)
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print("✅ GENERATION COMPLETE!")
|
||||||
|
print(f"{'='*60}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
412
skills/design-pattern-learner/skill.md
Normal file
412
skills/design-pattern-learner/skill.md
Normal file
@@ -0,0 +1,412 @@
|
|||||||
|
---
|
||||||
|
name: design-pattern-learner
|
||||||
|
description: "Studies and implements web design patterns from external sources. Fetches gists/repositories, analyzes design systems, extracts reusable patterns, and implements with Tailwind CSS. Auto-triggers on design study requests."
|
||||||
|
priority: 7
|
||||||
|
autoTrigger: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design Pattern Learner
|
||||||
|
|
||||||
|
**Status:** 🟢 **AUTO-ACTIVE** - Automatically triggers when user wants to study/learn from external design sources
|
||||||
|
|
||||||
|
**Auto-invoke:** When user asks to study, learn from, copy, or replicate designs from external sources (gists, repositories, URLs)
|
||||||
|
|
||||||
|
## What This Skill Does
|
||||||
|
|
||||||
|
The Design Pattern Learner skill enables Claude Code to:
|
||||||
|
|
||||||
|
1. **Fetch External Design Sources** - Retrieve gists, repositories, or web pages
|
||||||
|
2. **Analyze Design Patterns** - Extract layout, styling, animation, and component patterns
|
||||||
|
3. **Learn Design Systems** - Understand color palettes, typography, spacing, and design tokens
|
||||||
|
4. **Implement Patterns** - Apply learned patterns with Tailwind CSS or other frameworks
|
||||||
|
5. **Maintain Attribution** - Track sources and licenses properly
|
||||||
|
|
||||||
|
## Auto-Trigger Patterns
|
||||||
|
|
||||||
|
This skill automatically activates when user says:
|
||||||
|
|
||||||
|
- "study design from [URL/gist/repo]"
|
||||||
|
- "learn from [source]"
|
||||||
|
- "implement this design"
|
||||||
|
- "copy style from"
|
||||||
|
- "replicate this pattern"
|
||||||
|
- "analyze this [website/page/component]"
|
||||||
|
- "extract design patterns from"
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
### Phase 1: Source Acquisition
|
||||||
|
|
||||||
|
```
|
||||||
|
Given: URL, gist, or repository reference
|
||||||
|
1. Fetch the source content
|
||||||
|
2. Parse HTML/CSS/JS or code files
|
||||||
|
3. Identify design-related files (styles, components, layouts)
|
||||||
|
4. Cache for analysis
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Pattern Analysis
|
||||||
|
|
||||||
|
```
|
||||||
|
Extract Design Tokens:
|
||||||
|
- Colors (primary, secondary, accents)
|
||||||
|
- Typography (fonts, sizes, weights, line-heights)
|
||||||
|
- Spacing (margins, padding, gaps)
|
||||||
|
- Borders (radius, width, style)
|
||||||
|
- Shadows (box-shadows, text-shadows)
|
||||||
|
|
||||||
|
Identify Components:
|
||||||
|
- Buttons, cards, forms, modals, navigation
|
||||||
|
- Layout structures (grids, flexbox, containers)
|
||||||
|
- Animations and transitions
|
||||||
|
- Responsive breakpoints
|
||||||
|
|
||||||
|
Detect Patterns:
|
||||||
|
- Design system usage
|
||||||
|
- Component variants
|
||||||
|
- Hover/active states
|
||||||
|
- Dark mode support
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Pattern Extraction
|
||||||
|
|
||||||
|
```
|
||||||
|
Create Pattern Library:
|
||||||
|
1. Document each component with:
|
||||||
|
- HTML structure
|
||||||
|
- CSS/Tailwind classes
|
||||||
|
- Design tokens used
|
||||||
|
- Variations and states
|
||||||
|
- Usage examples
|
||||||
|
|
||||||
|
2. Generate reusable code:
|
||||||
|
- Tailwind component snippets
|
||||||
|
- Custom CSS when needed
|
||||||
|
- JavaScript for interactions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Implementation
|
||||||
|
|
||||||
|
```
|
||||||
|
Apply to User Project:
|
||||||
|
1. Match user's tech stack (Tailwind, CSS-in-JS, etc.)
|
||||||
|
2. Convert patterns to user's framework
|
||||||
|
3. Integrate with existing design system
|
||||||
|
4. Provide implementation guidance
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Example 1: Study from Gist
|
||||||
|
|
||||||
|
```
|
||||||
|
User: "Study the design patterns from https://gist.github.com/ivanfioravanti/abc123"
|
||||||
|
|
||||||
|
Skill executes:
|
||||||
|
1. Fetches gist content
|
||||||
|
2. Analyzes HTML/CSS structure
|
||||||
|
3. Extracts design tokens
|
||||||
|
4. Documents components found
|
||||||
|
5. Creates pattern library
|
||||||
|
6. Shows how to implement in user's project
|
||||||
|
|
||||||
|
Output:
|
||||||
|
- Design token summary (colors, fonts, spacing)
|
||||||
|
- Component catalog with code
|
||||||
|
- Implementation guide for user's stack
|
||||||
|
- Attribution to original source
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Replicate Component
|
||||||
|
|
||||||
|
```
|
||||||
|
User: "Replicate this hero section from https://example.com"
|
||||||
|
|
||||||
|
Skill executes:
|
||||||
|
1. Fetches the page
|
||||||
|
2. Isolates hero section
|
||||||
|
3. Analyzes structure and styling
|
||||||
|
4. Extracts responsive behavior
|
||||||
|
5. Creates Tailwind implementation
|
||||||
|
|
||||||
|
Output:
|
||||||
|
- Complete hero component code
|
||||||
|
- Design tokens used
|
||||||
|
- Responsive breakpoints
|
||||||
|
- Animation effects
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Learn Design System
|
||||||
|
|
||||||
|
```
|
||||||
|
User: "Learn the design system from this repository"
|
||||||
|
|
||||||
|
Skill executes:
|
||||||
|
1. Scans repository for design files
|
||||||
|
2. Extracts design tokens
|
||||||
|
3. Maps components to patterns
|
||||||
|
4. Creates design system documentation
|
||||||
|
|
||||||
|
Output:
|
||||||
|
- Design system overview
|
||||||
|
- Component library
|
||||||
|
- Design token reference
|
||||||
|
- Usage guidelines
|
||||||
|
```
|
||||||
|
|
||||||
|
## Analysis Capabilities
|
||||||
|
|
||||||
|
### Design Token Extraction
|
||||||
|
|
||||||
|
**Colors:**
|
||||||
|
- Primary/secondary/tertiary palettes
|
||||||
|
- Semantic colors (success, warning, error)
|
||||||
|
- Gradient definitions
|
||||||
|
- Dark mode variants
|
||||||
|
|
||||||
|
**Typography:**
|
||||||
|
- Font families
|
||||||
|
- Size scale (text-xs to text-9xl)
|
||||||
|
- Weight scale (100-900)
|
||||||
|
- Line-height ratios
|
||||||
|
- Letter-spacing
|
||||||
|
|
||||||
|
**Spacing:**
|
||||||
|
- Spacing scale (0-96)
|
||||||
|
- Margin/padding patterns
|
||||||
|
- Gap values for flex/grid
|
||||||
|
- Container sizing
|
||||||
|
|
||||||
|
**Effects:**
|
||||||
|
- Box shadows (sm, md, lg, xl, 2xl)
|
||||||
|
- Border radius scale
|
||||||
|
- Opacity levels
|
||||||
|
- Blur effects
|
||||||
|
|
||||||
|
### Component Detection
|
||||||
|
|
||||||
|
**UI Elements:**
|
||||||
|
- Buttons (variants, sizes, states)
|
||||||
|
- Cards (layouts, effects)
|
||||||
|
- Forms (inputs, labels, validation)
|
||||||
|
- Navigation (menus, breadcrumbs, tabs)
|
||||||
|
- Modals/overlays
|
||||||
|
- Lists/tables
|
||||||
|
- Alerts/badges
|
||||||
|
|
||||||
|
**Layout Patterns:**
|
||||||
|
- Container systems
|
||||||
|
- Grid layouts
|
||||||
|
- Flexbox patterns
|
||||||
|
- Responsive breakpoints
|
||||||
|
- Header/footer structures
|
||||||
|
|
||||||
|
### Animation Analysis
|
||||||
|
|
||||||
|
**Transitions:**
|
||||||
|
- Duration/timing functions
|
||||||
|
- Easing curves
|
||||||
|
- Transform patterns
|
||||||
|
- Opacity fades
|
||||||
|
|
||||||
|
**Interactions:**
|
||||||
|
- Hover effects
|
||||||
|
- Active states
|
||||||
|
- Focus states
|
||||||
|
- Loading animations
|
||||||
|
|
||||||
|
## Output Formats
|
||||||
|
|
||||||
|
### Pattern Documentation
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## [Component Name]
|
||||||
|
|
||||||
|
**Source:** [URL/Attribution]
|
||||||
|
**License:** [License if applicable]
|
||||||
|
|
||||||
|
### Design Tokens
|
||||||
|
- Colors: primary-500, gray-900
|
||||||
|
- Spacing: 4, 8, 16, 24, 32
|
||||||
|
- Radius: rounded-lg
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
```html
|
||||||
|
[HTML structure]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tailwind Implementation
|
||||||
|
```html
|
||||||
|
[Tailwind classes]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Variants
|
||||||
|
- Default
|
||||||
|
- Hover
|
||||||
|
- Active
|
||||||
|
- Disabled
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementation Guide
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Implementation for [Your Stack]
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
- Tailwind CSS v3+
|
||||||
|
- Required plugins
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
1. Copy component to `components/`
|
||||||
|
2. Add to Tailwind config if needed
|
||||||
|
3. Import and use
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
- Modify colors in config
|
||||||
|
- Adjust spacing scale
|
||||||
|
- Update breakpoints
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with Other Skills
|
||||||
|
|
||||||
|
**Works alongside:**
|
||||||
|
- `ui-ux-pro-max` - Provides design guidance and best practices
|
||||||
|
- `codebase-indexer` - Finds relevant files in user's project
|
||||||
|
- `auto-dispatcher` - Coordinates with other agents
|
||||||
|
|
||||||
|
**Trigger order:**
|
||||||
|
1. User mentions external design source
|
||||||
|
2. `design-pattern-learner` activates
|
||||||
|
3. Fetches and analyzes source
|
||||||
|
4. `ui-ux-pro-max` provides design guidance
|
||||||
|
5. `codebase-indexer` finds implementation location
|
||||||
|
6. Generates implementation code
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Attribution
|
||||||
|
- Always credit original sources
|
||||||
|
- Note licenses when applicable
|
||||||
|
- Link to original implementation
|
||||||
|
|
||||||
|
### Adaptation
|
||||||
|
- Adapt to user's design system
|
||||||
|
- Match user's tech stack
|
||||||
|
- Respect user's preferences
|
||||||
|
- Maintain consistency
|
||||||
|
|
||||||
|
### Quality
|
||||||
|
- Test responsive behavior
|
||||||
|
- Ensure accessibility
|
||||||
|
- Validate performance
|
||||||
|
- Check browser compatibility
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
**Source unavailable:**
|
||||||
|
- Provide alternative approach
|
||||||
|
- Suggest similar patterns
|
||||||
|
- Offer manual input option
|
||||||
|
|
||||||
|
**Complex design:**
|
||||||
|
- Break into smaller components
|
||||||
|
- Analyze incrementally
|
||||||
|
- Provide step-by-step guide
|
||||||
|
|
||||||
|
**License restrictions:**
|
||||||
|
- Note license terms
|
||||||
|
- Suggest alternatives
|
||||||
|
- Create inspired version
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
### Analyze URL
|
||||||
|
```bash
|
||||||
|
# Direct URL analysis
|
||||||
|
python3 skills/design-pattern-learner/scripts/analyze.py "https://example.com"
|
||||||
|
|
||||||
|
# Gist analysis
|
||||||
|
python3 skills/design-pattern-learner/scripts/analyze.py "https://gist.github.com/user/id"
|
||||||
|
|
||||||
|
# Repository analysis
|
||||||
|
python3 skills/design-pattern-learner/scripts/analyze.py "https://github.com/user/repo"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extract Component
|
||||||
|
```bash
|
||||||
|
# Extract specific component
|
||||||
|
python3 skills/design-pattern-learner/scripts/extract.py "https://example.com" --component "hero"
|
||||||
|
|
||||||
|
# Extract multiple components
|
||||||
|
python3 skills/design-pattern-learner/scripts/extract.py "https://example.com" --components "hero,footer,nav"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generate Implementation
|
||||||
|
```bash
|
||||||
|
# Generate for Tailwind
|
||||||
|
python3 skills/design-pattern-learner/scripts/generate.py --source "pattern.json" --framework "tailwind"
|
||||||
|
|
||||||
|
# Generate for React
|
||||||
|
python3 skills/design-pattern-learner/scripts/generate.py --source "pattern.json" --framework "react"
|
||||||
|
|
||||||
|
# Generate for Vue
|
||||||
|
python3 skills/design-pattern-learner/scripts/generate.py --source "pattern.json" --framework "vue"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Data Storage
|
||||||
|
|
||||||
|
**Pattern Library:** `~/.claude/skills/design-pattern-learner/data/patterns/`
|
||||||
|
- JSON files for learned patterns
|
||||||
|
- Indexed by source URL
|
||||||
|
- Version controlled
|
||||||
|
|
||||||
|
**Source Cache:** `~/.claude/skills/design-pattern-learner/data/sources/`
|
||||||
|
- Cached fetched content
|
||||||
|
- HTML/CSS/JS files
|
||||||
|
- Timestamped for refresh
|
||||||
|
|
||||||
|
**Learning Log:** `~/.claude/skills/design-pattern-learner/learning-history.jsonl`
|
||||||
|
- Record of all sources studied
|
||||||
|
- Patterns extracted
|
||||||
|
- Implementation success rate
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
**Typical analysis time:**
|
||||||
|
- Simple component: 5-10 seconds
|
||||||
|
- Full page: 15-30 seconds
|
||||||
|
- Design system: 30-60 seconds
|
||||||
|
|
||||||
|
**Cache benefits:**
|
||||||
|
- Reuse previously analyzed sources
|
||||||
|
- Incremental updates only
|
||||||
|
- Pattern matching across sources
|
||||||
|
|
||||||
|
## Contributing Patterns
|
||||||
|
|
||||||
|
**To add new pattern sources:**
|
||||||
|
1. Verify license compatibility
|
||||||
|
2. Test extraction quality
|
||||||
|
3. Document pattern usage
|
||||||
|
4. Add to pattern library
|
||||||
|
|
||||||
|
**Pattern quality criteria:**
|
||||||
|
- Modern and current
|
||||||
|
- Well-structured code
|
||||||
|
- Responsive design
|
||||||
|
- Accessible implementation
|
||||||
|
- Clear documentation
|
||||||
|
|
||||||
|
## Version History
|
||||||
|
|
||||||
|
**v1.0.0** - Initial release
|
||||||
|
- External source fetching
|
||||||
|
- Pattern analysis
|
||||||
|
- Design token extraction
|
||||||
|
- Component cataloging
|
||||||
|
- Implementation generation
|
||||||
|
- Attribution tracking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Remember:** Always respect licenses and attribute sources appropriately. This skill is for learning and inspiration, not for copying proprietary designs without permission.
|
||||||
Reference in New Issue
Block a user