码巢引擎2026年开发文档
00-开发规范
后端规范
README
后端开发手册
前端规范
README
TypeScript最佳实践
前端布局规范
前端页面模板
前端颜色与组件规范
核心规范
组件配置手册
问题排查指南
页面模板
最佳实践
README
bp-20260223-m7ps
图片上传优化总结
BUG自动记录系统使用指南
README
TYPE_SAFETY_GUIDE
常见BUG知识库
常见BUG知识库
开发前检查清单
开发安全规范
开发规范-完整版-含FutureBirdAadminAi部署
数据模型字典
文档分类规范
文档标准化规范
文档模板-基础版
文档模板-技术版
类型安全快速参考卡
类型安全规范体系
规范更新指南
过期文档清理机制
错误处理规范
错误预防指南
常见BUG知识库
常见BUG知识库
01-快速开始
Gitee快速开始
README
协作快速开始
快速开始
质量保证快速开始
02-部署指南
Docker更新指南
Docker部署
FutureBirdAadminAi部署指南
FutureBirdAadminAi部署问题分析
README
发布指南
宝塔Docker部署教程
宝塔PM2部署教程
宝塔图形化部署教程
快速发布指南
数据库和依赖变更处理指南
构建和发布
构建标准
构建检查清单
生产部署快速开始
生产部署方案
生产部署标准
生产部署检查清单
程序备份性能
自动修复和发布指南
自动化发布命令使用指南
部署快速开始
部署指南
项目更新部署指南
03-开发指南
Git凭据配置
Git推送规则
Git自动配置
README
全局样式
协作设置
定时任务
开发指南
开发流程
开发环境标准
技术改进
贡献指南
项目目录树
项目目录结构
04-API文档
API接口文档
README
hr-api
企业API
05-数据库
DATABASE_SCHEMA
README
分区指南
数据库字典
数据持久化
数据模型统一
数据迁移
06-架构设计
RBAC-PERMISSIONS
README
SaaS客户引导流程设计
companyId统一规范
employee-permission-system-design
enterprise-data-linkage
仓库实现总结
仓库模式
企业管理端员工权限系统分析
前端架构
前端重构总结
员工权限系统评估报告
员工管理菜单重构方案
权限系统混乱问题分析
架构优化计划
架构使用指南
架构结构
架构结构
状态管理
用户身份管理体系
系统架构
面试管理模块重构规划
项目技术栈
07-测试质量
README
测试修复标准
测试报告
质量保证系统
08-版本管理
CHANGELOG
README
VERSION_RULES
09-配置指南
README
SMTP配置指南
主题切换指南
渠道配置指南
环境变量指南
环境隔离
12-项目记忆
README
知识库导入指南
记忆系统指南
13-迁移指南
README
备份迁移指南
管理员迁移指南
迁移快速开始
17-其他
README
压缩摘要
18-开放平台
01-架构设计
02-API接口设计
03-安全机制
04-前端设计
05-数据库设计
开放平台API指南
开放平台API说明
19-智能进化
AI执行规则
AI进化机制
README
自动化实现总览
黄金规则
40-操作教程
README
微信公众号域名配置指南
微信本地开发调试指南
44-技能文件
alipay-payment-integration
references
checklist
SKILL
audio
python
README
typescript
README
SKILL
database
python
README
typescript
README
SKILL
design-style-thinking
SKILL
doctor
references
sql-patterns
SKILL
document-generation
python
README
SKILL
email
SKILL
embedding
python
README
typescript
README
SKILL
expo-advanced
references
audio-record-play
file-upload
masonry-layout
save-to-gallery
top-tab-navigation
SKILL
feishu-base
SKILL
feishu-message
SKILL
fetch-url
python
README
typescript
README
SKILL
frontend-design
LICENSE
SKILL
FutureBird-coding-web-performance-best-practice
SKILL
general-dev-preview
references
web-preview
SKILL
image-generation
python
README
typescript
README
SKILL
knowledge
references
python
README
typescript
README
cli
SKILL
llm
python
README
typescript
README
SKILL
miniapp-upload-asr
SKILL
pptx-generation
python
README
SKILL
project-memory-loader
scripts
project_memory_loader
SKILL
repair
scripts
merge-commit-map
SKILL
shadcn-web-base-theme
assets
colors
amber
artistic-green
bento-blue
blue
cyan
emerald
fuchsia
gray
green
indigo
lime
low-pink
neutral
orange
purple
red
retro-brown
rose
sky
supbase-green
teal
tech-purple
vintage-grey
violet
yellow
fonts
business
classic
playful
radius
2xl
2xs
lg
md
none
sm
xl
xs
shadow
artistic
bento
cool
retro
superbase
tech
tool
vintage
default
references
colors
fonts
quick
radius
shadows
scripts
theme
SKILL
package
skill-creator-coze
scripts
init_skill
quick_validate
SKILL
storage
python
README
typescript
README
SKILL
supabase
assets
supabase-client
supabase-client
references
_future
asset-supabase-browser
asset-supabase-config-inject
asset-supabase-config-route
python-auth
python-realtime
python-storage
typescript-auth
typescript-realtime
typescript-storage
typescript-supabase-browser
typescript-supabase-config-inject
typescript-supabase-config-route
python
README
database
edge-functions
orm-model-guide
supabase_client
typescript
README
database
drizzle-schema-guide
edge-functions
supabase-client
cli
rls
SKILL
supabase-auth
references
typescript
supabase-browser
supabase-config-inject
supabase-config-route
auth-config
verify-session
SKILL
ui-design-ref
reference
3D黏土风
克莱因蓝高定风
暗黑科技风
杂志风
极光柔和
柔和卡片
玻璃拟态
纯白极简风
自然有机
SKILL
ui-ux-pro-max
scripts
core
design_system
search
SKILL
vercel-composition-patterns
rules
architecture-avoid-boolean-props
architecture-compound-components
patterns-children-over-render-props
patterns-explicit-variants
react19-no-forwardref
state-context-interface
state-decouple-implementation
state-lift-state
AGENTS
SKILL
vercel-react-best-practices
rules
advanced-event-handler-refs
advanced-init-once
advanced-use-latest
async-api-routes
async-defer-await
async-dependencies
async-parallel
async-suspense-boundaries
bundle-barrel-imports
bundle-conditional
bundle-defer-third-party
bundle-dynamic-imports
bundle-preload
client-event-listeners
client-localstorage-schema
client-passive-event-listeners
client-swr-dedup
js-batch-dom-css
js-cache-function-results
js-cache-property-access
js-cache-storage
js-combine-iterations
js-early-exit
js-hoist-regexp
js-index-maps
js-length-check-first
js-min-max-loop
js-set-map-lookups
js-tosorted-immutable
rendering-activity
rendering-animate-svg-wrapper
rendering-conditional-render
rendering-content-visibility
rendering-hoist-jsx
rendering-hydration-no-flicker
rendering-hydration-suppress-warning
rendering-svg-precision
rendering-usetransition-loading
rerender-defer-reads
rerender-dependencies
rerender-derived-state-no-effect
rerender-derived-state
rerender-functional-setstate
rerender-lazy-state-init
rerender-memo-with-default-value
rerender-memo
rerender-move-effect-to-event
rerender-simple-expression-in-memo
rerender-transitions
rerender-use-ref-transient-values
server-auth-actions
server-cache-lru
server-cache-react
server-dedup-props
server-parallel-fetching
server-serialization
AGENTS
SKILL
video-edit
python
README
typescript
README
SKILL
video-generation
python
README
typescript
README
SKILL
volcano-ark
SKILL
web-design-guidelines
SKILL
web-search
python
README
typescript
README
SKILL
webrtc-best-practice
SKILL
websocket-guide
references
nextjs
nodejs
SKILL
wechat-bot
SKILL
wechat-official-account
SKILL
README
README
未来鸟:企业数字化转型奔腾的力量!
-
+
首页
design_system
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Design System Generator - Aggregates search results and applies reasoning to generate comprehensive design system recommendations. Usage: from design_system import generate_design_system result = generate_design_system("SaaS dashboard", "My Project") # With persistence (Master + Overrides pattern) result = generate_design_system("SaaS dashboard", "My Project", persist=True) result = generate_design_system("SaaS dashboard", "My Project", persist=True, page="dashboard") """ import csv import json import os from datetime import datetime from pathlib import Path from core import search, DATA_DIR # ============ CONFIGURATION ============ REASONING_FILE = "ui-reasoning.csv" SEARCH_CONFIG = { "product": {"max_results": 1}, "style": {"max_results": 3}, "color": {"max_results": 2}, "landing": {"max_results": 2}, "typography": {"max_results": 2} } # ============ DESIGN SYSTEM GENERATOR ============ class DesignSystemGenerator: """Generates design system recommendations from aggregated searches.""" def __init__(self): self.reasoning_data = self._load_reasoning() def _load_reasoning(self) -> list: """Load reasoning rules from CSV.""" filepath = DATA_DIR / REASONING_FILE if not filepath.exists(): return [] with open(filepath, 'r', encoding='utf-8') as f: return list(csv.DictReader(f)) def _multi_domain_search(self, query: str, style_priority: list = None) -> dict: """Execute searches across multiple domains.""" results = {} for domain, config in SEARCH_CONFIG.items(): if domain == "style" and style_priority: # For style, also search with priority keywords priority_query = " ".join(style_priority[:2]) if style_priority else query combined_query = f"{query} {priority_query}" results[domain] = search(combined_query, domain, config["max_results"]) else: results[domain] = search(query, domain, config["max_results"]) return results def _find_reasoning_rule(self, category: str) -> dict: """Find matching reasoning rule for a category.""" category_lower = category.lower() # Try exact match first for rule in self.reasoning_data: if rule.get("UI_Category", "").lower() == category_lower: return rule # Try partial match for rule in self.reasoning_data: ui_cat = rule.get("UI_Category", "").lower() if ui_cat in category_lower or category_lower in ui_cat: return rule # Try keyword match for rule in self.reasoning_data: ui_cat = rule.get("UI_Category", "").lower() keywords = ui_cat.replace("/", " ").replace("-", " ").split() if any(kw in category_lower for kw in keywords): return rule return {} def _apply_reasoning(self, category: str, search_results: dict) -> dict: """Apply reasoning rules to search results.""" rule = self._find_reasoning_rule(category) if not rule: return { "pattern": "Hero + Features + CTA", "style_priority": ["Minimalism", "Flat Design"], "color_mood": "Professional", "typography_mood": "Clean", "key_effects": "Subtle hover transitions", "anti_patterns": "", "decision_rules": {}, "severity": "MEDIUM" } # Parse decision rules JSON decision_rules = {} try: decision_rules = json.loads(rule.get("Decision_Rules", "{}")) except json.JSONDecodeError: pass return { "pattern": rule.get("Recommended_Pattern", ""), "style_priority": [s.strip() for s in rule.get("Style_Priority", "").split("+")], "color_mood": rule.get("Color_Mood", ""), "typography_mood": rule.get("Typography_Mood", ""), "key_effects": rule.get("Key_Effects", ""), "anti_patterns": rule.get("Anti_Patterns", ""), "decision_rules": decision_rules, "severity": rule.get("Severity", "MEDIUM") } def _select_best_match(self, results: list, priority_keywords: list) -> dict: """Select best matching result based on priority keywords.""" if not results: return {} if not priority_keywords: return results[0] # First: try exact style name match for priority in priority_keywords: priority_lower = priority.lower().strip() for result in results: style_name = result.get("Style Category", "").lower() if priority_lower in style_name or style_name in priority_lower: return result # Second: score by keyword match in all fields scored = [] for result in results: result_str = str(result).lower() score = 0 for kw in priority_keywords: kw_lower = kw.lower().strip() # Higher score for style name match if kw_lower in result.get("Style Category", "").lower(): score += 10 # Lower score for keyword field match elif kw_lower in result.get("Keywords", "").lower(): score += 3 # Even lower for other field matches elif kw_lower in result_str: score += 1 scored.append((score, result)) scored.sort(key=lambda x: x[0], reverse=True) return scored[0][1] if scored and scored[0][0] > 0 else results[0] def _extract_results(self, search_result: dict) -> list: """Extract results list from search result dict.""" return search_result.get("results", []) def generate(self, query: str, project_name: str = None) -> dict: """Generate complete design system recommendation.""" # Step 1: First search product to get category product_result = search(query, "product", 1) product_results = product_result.get("results", []) category = "General" if product_results: category = product_results[0].get("Product Type", "General") # Step 2: Get reasoning rules for this category reasoning = self._apply_reasoning(category, {}) style_priority = reasoning.get("style_priority", []) # Step 3: Multi-domain search with style priority hints search_results = self._multi_domain_search(query, style_priority) search_results["product"] = product_result # Reuse product search # Step 4: Select best matches from each domain using priority style_results = self._extract_results(search_results.get("style", {})) color_results = self._extract_results(search_results.get("color", {})) typography_results = self._extract_results(search_results.get("typography", {})) landing_results = self._extract_results(search_results.get("landing", {})) best_style = self._select_best_match(style_results, reasoning.get("style_priority", [])) best_color = color_results[0] if color_results else {} best_typography = typography_results[0] if typography_results else {} best_landing = landing_results[0] if landing_results else {} # Step 5: Build final recommendation # Combine effects from both reasoning and style search style_effects = best_style.get("Effects & Animation", "") reasoning_effects = reasoning.get("key_effects", "") combined_effects = style_effects if style_effects else reasoning_effects return { "project_name": project_name or query.upper(), "category": category, "pattern": { "name": best_landing.get("Pattern Name", reasoning.get("pattern", "Hero + Features + CTA")), "sections": best_landing.get("Section Order", "Hero > Features > CTA"), "cta_placement": best_landing.get("Primary CTA Placement", "Above fold"), "color_strategy": best_landing.get("Color Strategy", ""), "conversion": best_landing.get("Conversion Optimization", "") }, "style": { "name": best_style.get("Style Category", "Minimalism"), "type": best_style.get("Type", "General"), "effects": style_effects, "keywords": best_style.get("Keywords", ""), "best_for": best_style.get("Best For", ""), "performance": best_style.get("Performance", ""), "accessibility": best_style.get("Accessibility", "") }, "colors": { "primary": best_color.get("Primary (Hex)", "#2563EB"), "secondary": best_color.get("Secondary (Hex)", "#3B82F6"), "cta": best_color.get("CTA (Hex)", "#F97316"), "background": best_color.get("Background (Hex)", "#F8FAFC"), "text": best_color.get("Text (Hex)", "#1E293B"), "notes": best_color.get("Notes", "") }, "typography": { "heading": best_typography.get("Heading Font", "Inter"), "body": best_typography.get("Body Font", "Inter"), "mood": best_typography.get("Mood/Style Keywords", reasoning.get("typography_mood", "")), "best_for": best_typography.get("Best For", ""), "google_fonts_url": best_typography.get("Google Fonts URL", ""), "css_import": best_typography.get("CSS Import", "") }, "key_effects": combined_effects, "anti_patterns": reasoning.get("anti_patterns", ""), "decision_rules": reasoning.get("decision_rules", {}), "severity": reasoning.get("severity", "MEDIUM") } # ============ OUTPUT FORMATTERS ============ BOX_WIDTH = 90 # Wider box for more content def format_ascii_box(design_system: dict) -> str: """Format design system as ASCII box with emojis (MCP-style).""" project = design_system.get("project_name", "PROJECT") pattern = design_system.get("pattern", {}) style = design_system.get("style", {}) colors = design_system.get("colors", {}) typography = design_system.get("typography", {}) effects = design_system.get("key_effects", "") anti_patterns = design_system.get("anti_patterns", "") def wrap_text(text: str, prefix: str, width: int) -> list: """Wrap long text into multiple lines.""" if not text: return [] words = text.split() lines = [] current_line = prefix for word in words: if len(current_line) + len(word) + 1 <= width - 2: current_line += (" " if current_line != prefix else "") + word else: if current_line != prefix: lines.append(current_line) current_line = prefix + word if current_line != prefix: lines.append(current_line) return lines # Build sections from pattern sections = pattern.get("sections", "").split(">") sections = [s.strip() for s in sections if s.strip()] # Build output lines lines = [] w = BOX_WIDTH - 1 lines.append("+" + "-" * w + "+") lines.append(f"| TARGET: {project} - RECOMMENDED DESIGN SYSTEM".ljust(BOX_WIDTH) + "|") lines.append("+" + "-" * w + "+") lines.append("|" + " " * BOX_WIDTH + "|") # Pattern section lines.append(f"| PATTERN: {pattern.get('name', '')}".ljust(BOX_WIDTH) + "|") if pattern.get('conversion'): lines.append(f"| Conversion: {pattern.get('conversion', '')}".ljust(BOX_WIDTH) + "|") if pattern.get('cta_placement'): lines.append(f"| CTA: {pattern.get('cta_placement', '')}".ljust(BOX_WIDTH) + "|") lines.append("| Sections:".ljust(BOX_WIDTH) + "|") for i, section in enumerate(sections, 1): lines.append(f"| {i}. {section}".ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Style section lines.append(f"| STYLE: {style.get('name', '')}".ljust(BOX_WIDTH) + "|") if style.get("keywords"): for line in wrap_text(f"Keywords: {style.get('keywords', '')}", "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") if style.get("best_for"): for line in wrap_text(f"Best For: {style.get('best_for', '')}", "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") if style.get("performance") or style.get("accessibility"): perf_a11y = f"Performance: {style.get('performance', '')} | Accessibility: {style.get('accessibility', '')}" lines.append(f"| {perf_a11y}".ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Colors section lines.append("| COLORS:".ljust(BOX_WIDTH) + "|") lines.append(f"| Primary: {colors.get('primary', '')}".ljust(BOX_WIDTH) + "|") lines.append(f"| Secondary: {colors.get('secondary', '')}".ljust(BOX_WIDTH) + "|") lines.append(f"| CTA: {colors.get('cta', '')}".ljust(BOX_WIDTH) + "|") lines.append(f"| Background: {colors.get('background', '')}".ljust(BOX_WIDTH) + "|") lines.append(f"| Text: {colors.get('text', '')}".ljust(BOX_WIDTH) + "|") if colors.get("notes"): for line in wrap_text(f"Notes: {colors.get('notes', '')}", "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Typography section lines.append(f"| TYPOGRAPHY: {typography.get('heading', '')} / {typography.get('body', '')}".ljust(BOX_WIDTH) + "|") if typography.get("mood"): for line in wrap_text(f"Mood: {typography.get('mood', '')}", "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") if typography.get("best_for"): for line in wrap_text(f"Best For: {typography.get('best_for', '')}", "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") if typography.get("google_fonts_url"): lines.append(f"| Google Fonts: {typography.get('google_fonts_url', '')}".ljust(BOX_WIDTH) + "|") if typography.get("css_import"): lines.append(f"| CSS Import: {typography.get('css_import', '')[:70]}...".ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Key Effects section if effects: lines.append("| KEY EFFECTS:".ljust(BOX_WIDTH) + "|") for line in wrap_text(effects, "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Anti-patterns section if anti_patterns: lines.append("| AVOID (Anti-patterns):".ljust(BOX_WIDTH) + "|") for line in wrap_text(anti_patterns, "| ", BOX_WIDTH): lines.append(line.ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") # Pre-Delivery Checklist section lines.append("| PRE-DELIVERY CHECKLIST:".ljust(BOX_WIDTH) + "|") checklist_items = [ "[ ] No emojis as icons (use SVG: Heroicons/Lucide)", "[ ] cursor-pointer on all clickable elements", "[ ] Hover states with smooth transitions (150-300ms)", "[ ] Light mode: text contrast 4.5:1 minimum", "[ ] Focus states visible for keyboard nav", "[ ] prefers-reduced-motion respected", "[ ] Responsive: 375px, 768px, 1024px, 1440px" ] for item in checklist_items: lines.append(f"| {item}".ljust(BOX_WIDTH) + "|") lines.append("|" + " " * BOX_WIDTH + "|") lines.append("+" + "-" * w + "+") return "\n".join(lines) def format_markdown(design_system: dict) -> str: """Format design system as markdown.""" project = design_system.get("project_name", "PROJECT") pattern = design_system.get("pattern", {}) style = design_system.get("style", {}) colors = design_system.get("colors", {}) typography = design_system.get("typography", {}) effects = design_system.get("key_effects", "") anti_patterns = design_system.get("anti_patterns", "") lines = [] lines.append(f"## Design System: {project}") lines.append("") # Pattern section lines.append("### Pattern") lines.append(f"- **Name:** {pattern.get('name', '')}") if pattern.get('conversion'): lines.append(f"- **Conversion Focus:** {pattern.get('conversion', '')}") if pattern.get('cta_placement'): lines.append(f"- **CTA Placement:** {pattern.get('cta_placement', '')}") if pattern.get('color_strategy'): lines.append(f"- **Color Strategy:** {pattern.get('color_strategy', '')}") lines.append(f"- **Sections:** {pattern.get('sections', '')}") lines.append("") # Style section lines.append("### Style") lines.append(f"- **Name:** {style.get('name', '')}") if style.get('keywords'): lines.append(f"- **Keywords:** {style.get('keywords', '')}") if style.get('best_for'): lines.append(f"- **Best For:** {style.get('best_for', '')}") if style.get('performance') or style.get('accessibility'): lines.append(f"- **Performance:** {style.get('performance', '')} | **Accessibility:** {style.get('accessibility', '')}") lines.append("") # Colors section lines.append("### Colors") lines.append(f"| Role | Hex |") lines.append(f"|------|-----|") lines.append(f"| Primary | {colors.get('primary', '')} |") lines.append(f"| Secondary | {colors.get('secondary', '')} |") lines.append(f"| CTA | {colors.get('cta', '')} |") lines.append(f"| Background | {colors.get('background', '')} |") lines.append(f"| Text | {colors.get('text', '')} |") if colors.get("notes"): lines.append(f"\n*Notes: {colors.get('notes', '')}*") lines.append("") # Typography section lines.append("### Typography") lines.append(f"- **Heading:** {typography.get('heading', '')}") lines.append(f"- **Body:** {typography.get('body', '')}") if typography.get("mood"): lines.append(f"- **Mood:** {typography.get('mood', '')}") if typography.get("best_for"): lines.append(f"- **Best For:** {typography.get('best_for', '')}") if typography.get("google_fonts_url"): lines.append(f"- **Google Fonts:** {typography.get('google_fonts_url', '')}") if typography.get("css_import"): lines.append(f"- **CSS Import:**") lines.append(f"```css") lines.append(f"{typography.get('css_import', '')}") lines.append(f"```") lines.append("") # Key Effects section if effects: lines.append("### Key Effects") lines.append(f"{effects}") lines.append("") # Anti-patterns section if anti_patterns: lines.append("### Avoid (Anti-patterns)") newline_bullet = '\n- ' lines.append(f"- {anti_patterns.replace(' + ', newline_bullet)}") lines.append("") # Pre-Delivery Checklist section lines.append("### Pre-Delivery Checklist") lines.append("- [ ] No emojis as icons (use SVG: Heroicons/Lucide)") lines.append("- [ ] cursor-pointer on all clickable elements") lines.append("- [ ] Hover states with smooth transitions (150-300ms)") lines.append("- [ ] Light mode: text contrast 4.5:1 minimum") lines.append("- [ ] Focus states visible for keyboard nav") lines.append("- [ ] prefers-reduced-motion respected") lines.append("- [ ] Responsive: 375px, 768px, 1024px, 1440px") lines.append("") return "\n".join(lines) # ============ MAIN ENTRY POINT ============ def generate_design_system(query: str, project_name: str = None, output_format: str = "ascii", persist: bool = False, page: str = None, output_dir: str = None) -> str: """ Main entry point for design system generation. Args: query: Search query (e.g., "SaaS dashboard", "e-commerce luxury") project_name: Optional project name for output header output_format: "ascii" (default) or "markdown" persist: If True, save design system to design-system/ folder page: Optional page name for page-specific override file output_dir: Optional output directory (defaults to current working directory) Returns: Formatted design system string """ generator = DesignSystemGenerator() design_system = generator.generate(query, project_name) # Persist to files if requested if persist: persist_design_system(design_system, page, output_dir, query) if output_format == "markdown": return format_markdown(design_system) return format_ascii_box(design_system) # ============ PERSISTENCE FUNCTIONS ============ def persist_design_system(design_system: dict, page: str = None, output_dir: str = None, page_query: str = None) -> dict: """ Persist design system to design-system/<project>/ folder using Master + Overrides pattern. Args: design_system: The generated design system dictionary page: Optional page name for page-specific override file output_dir: Optional output directory (defaults to current working directory) page_query: Optional query string for intelligent page override generation Returns: dict with created file paths and status """ base_dir = Path(output_dir) if output_dir else Path.cwd() # Use project name for project-specific folder project_name = design_system.get("project_name", "default") project_slug = project_name.lower().replace(' ', '-') design_system_dir = base_dir / "design-system" / project_slug pages_dir = design_system_dir / "pages" created_files = [] # Create directories design_system_dir.mkdir(parents=True, exist_ok=True) pages_dir.mkdir(parents=True, exist_ok=True) master_file = design_system_dir / "MASTER.md" # Generate and write MASTER.md master_content = format_master_md(design_system) with open(master_file, 'w', encoding='utf-8') as f: f.write(master_content) created_files.append(str(master_file)) # If page is specified, create page override file with intelligent content if page: page_file = pages_dir / f"{page.lower().replace(' ', '-')}.md" page_content = format_page_override_md(design_system, page, page_query) with open(page_file, 'w', encoding='utf-8') as f: f.write(page_content) created_files.append(str(page_file)) return { "status": "success", "design_system_dir": str(design_system_dir), "created_files": created_files } def format_master_md(design_system: dict) -> str: """Format design system as MASTER.md with hierarchical override logic.""" project = design_system.get("project_name", "PROJECT") pattern = design_system.get("pattern", {}) style = design_system.get("style", {}) colors = design_system.get("colors", {}) typography = design_system.get("typography", {}) effects = design_system.get("key_effects", "") anti_patterns = design_system.get("anti_patterns", "") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") lines = [] # Logic header lines.append("# Design System Master File") lines.append("") lines.append("> **LOGIC:** When building a specific page, first check `design-system/pages/[page-name].md`.") lines.append("> If that file exists, its rules **override** this Master file.") lines.append("> If not, strictly follow the rules below.") lines.append("") lines.append("---") lines.append("") lines.append(f"**Project:** {project}") lines.append(f"**Generated:** {timestamp}") lines.append(f"**Category:** {design_system.get('category', 'General')}") lines.append("") lines.append("---") lines.append("") # Global Rules section lines.append("## Global Rules") lines.append("") # Color Palette lines.append("### Color Palette") lines.append("") lines.append("| Role | Hex | CSS Variable |") lines.append("|------|-----|--------------|") lines.append(f"| Primary | `{colors.get('primary', '#2563EB')}` | `--color-primary` |") lines.append(f"| Secondary | `{colors.get('secondary', '#3B82F6')}` | `--color-secondary` |") lines.append(f"| CTA/Accent | `{colors.get('cta', '#F97316')}` | `--color-cta` |") lines.append(f"| Background | `{colors.get('background', '#F8FAFC')}` | `--color-background` |") lines.append(f"| Text | `{colors.get('text', '#1E293B')}` | `--color-text` |") lines.append("") if colors.get("notes"): lines.append(f"**Color Notes:** {colors.get('notes', '')}") lines.append("") # Typography lines.append("### Typography") lines.append("") lines.append(f"- **Heading Font:** {typography.get('heading', 'Inter')}") lines.append(f"- **Body Font:** {typography.get('body', 'Inter')}") if typography.get("mood"): lines.append(f"- **Mood:** {typography.get('mood', '')}") if typography.get("google_fonts_url"): lines.append(f"- **Google Fonts:** [{typography.get('heading', '')} + {typography.get('body', '')}]({typography.get('google_fonts_url', '')})") lines.append("") if typography.get("css_import"): lines.append("**CSS Import:**") lines.append("```css") lines.append(typography.get("css_import", "")) lines.append("```") lines.append("") # Spacing Variables lines.append("### Spacing Variables") lines.append("") lines.append("| Token | Value | Usage |") lines.append("|-------|-------|-------|") lines.append("| `--space-xs` | `4px` / `0.25rem` | Tight gaps |") lines.append("| `--space-sm` | `8px` / `0.5rem` | Icon gaps, inline spacing |") lines.append("| `--space-md` | `16px` / `1rem` | Standard padding |") lines.append("| `--space-lg` | `24px` / `1.5rem` | Section padding |") lines.append("| `--space-xl` | `32px` / `2rem` | Large gaps |") lines.append("| `--space-2xl` | `48px` / `3rem` | Section margins |") lines.append("| `--space-3xl` | `64px` / `4rem` | Hero padding |") lines.append("") # Shadow Depths lines.append("### Shadow Depths") lines.append("") lines.append("| Level | Value | Usage |") lines.append("|-------|-------|-------|") lines.append("| `--shadow-sm` | `0 1px 2px rgba(0,0,0,0.05)` | Subtle lift |") lines.append("| `--shadow-md` | `0 4px 6px rgba(0,0,0,0.1)` | Cards, buttons |") lines.append("| `--shadow-lg` | `0 10px 15px rgba(0,0,0,0.1)` | Modals, dropdowns |") lines.append("| `--shadow-xl` | `0 20px 25px rgba(0,0,0,0.15)` | Hero images, featured cards |") lines.append("") # Component Specs section lines.append("---") lines.append("") lines.append("## Component Specs") lines.append("") # Buttons lines.append("### Buttons") lines.append("") lines.append("```css") lines.append("/* Primary Button */") lines.append(".btn-primary {") lines.append(f" background: {colors.get('cta', '#F97316')};") lines.append(" color: white;") lines.append(" padding: 12px 24px;") lines.append(" border-radius: 8px;") lines.append(" font-weight: 600;") lines.append(" transition: all 200ms ease;") lines.append(" cursor: pointer;") lines.append("}") lines.append("") lines.append(".btn-primary:hover {") lines.append(" opacity: 0.9;") lines.append(" transform: translateY(-1px);") lines.append("}") lines.append("") lines.append("/* Secondary Button */") lines.append(".btn-secondary {") lines.append(f" background: transparent;") lines.append(f" color: {colors.get('primary', '#2563EB')};") lines.append(f" border: 2px solid {colors.get('primary', '#2563EB')};") lines.append(" padding: 12px 24px;") lines.append(" border-radius: 8px;") lines.append(" font-weight: 600;") lines.append(" transition: all 200ms ease;") lines.append(" cursor: pointer;") lines.append("}") lines.append("```") lines.append("") # Cards lines.append("### Cards") lines.append("") lines.append("```css") lines.append(".card {") lines.append(f" background: {colors.get('background', '#FFFFFF')};") lines.append(" border-radius: 12px;") lines.append(" padding: 24px;") lines.append(" box-shadow: var(--shadow-md);") lines.append(" transition: all 200ms ease;") lines.append(" cursor: pointer;") lines.append("}") lines.append("") lines.append(".card:hover {") lines.append(" box-shadow: var(--shadow-lg);") lines.append(" transform: translateY(-2px);") lines.append("}") lines.append("```") lines.append("") # Inputs lines.append("### Inputs") lines.append("") lines.append("```css") lines.append(".input {") lines.append(" padding: 12px 16px;") lines.append(" border: 1px solid #E2E8F0;") lines.append(" border-radius: 8px;") lines.append(" font-size: 16px;") lines.append(" transition: border-color 200ms ease;") lines.append("}") lines.append("") lines.append(".input:focus {") lines.append(f" border-color: {colors.get('primary', '#2563EB')};") lines.append(" outline: none;") lines.append(f" box-shadow: 0 0 0 3px {colors.get('primary', '#2563EB')}20;") lines.append("}") lines.append("```") lines.append("") # Modals lines.append("### Modals") lines.append("") lines.append("```css") lines.append(".modal-overlay {") lines.append(" background: rgba(0, 0, 0, 0.5);") lines.append(" backdrop-filter: blur(4px);") lines.append("}") lines.append("") lines.append(".modal {") lines.append(" background: white;") lines.append(" border-radius: 16px;") lines.append(" padding: 32px;") lines.append(" box-shadow: var(--shadow-xl);") lines.append(" max-width: 500px;") lines.append(" width: 90%;") lines.append("}") lines.append("```") lines.append("") # Style section lines.append("---") lines.append("") lines.append("## Style Guidelines") lines.append("") lines.append(f"**Style:** {style.get('name', 'Minimalism')}") lines.append("") if style.get("keywords"): lines.append(f"**Keywords:** {style.get('keywords', '')}") lines.append("") if style.get("best_for"): lines.append(f"**Best For:** {style.get('best_for', '')}") lines.append("") if effects: lines.append(f"**Key Effects:** {effects}") lines.append("") # Layout Pattern lines.append("### Page Pattern") lines.append("") lines.append(f"**Pattern Name:** {pattern.get('name', '')}") lines.append("") if pattern.get('conversion'): lines.append(f"- **Conversion Strategy:** {pattern.get('conversion', '')}") if pattern.get('cta_placement'): lines.append(f"- **CTA Placement:** {pattern.get('cta_placement', '')}") lines.append(f"- **Section Order:** {pattern.get('sections', '')}") lines.append("") # Anti-Patterns section lines.append("---") lines.append("") lines.append("## Anti-Patterns (Do NOT Use)") lines.append("") if anti_patterns: anti_list = [a.strip() for a in anti_patterns.split("+")] for anti in anti_list: if anti: lines.append(f"- ❌ {anti}") lines.append("") lines.append("### Additional Forbidden Patterns") lines.append("") lines.append("- ❌ **Emojis as icons** — Use SVG icons (Heroicons, Lucide, Simple Icons)") lines.append("- ❌ **Missing cursor:pointer** — All clickable elements must have cursor:pointer") lines.append("- ❌ **Layout-shifting hovers** — Avoid scale transforms that shift layout") lines.append("- ❌ **Low contrast text** — Maintain 4.5:1 minimum contrast ratio") lines.append("- ❌ **Instant state changes** — Always use transitions (150-300ms)") lines.append("- ❌ **Invisible focus states** — Focus states must be visible for a11y") lines.append("") # Pre-Delivery Checklist lines.append("---") lines.append("") lines.append("## Pre-Delivery Checklist") lines.append("") lines.append("Before delivering any UI code, verify:") lines.append("") lines.append("- [ ] No emojis used as icons (use SVG instead)") lines.append("- [ ] All icons from consistent icon set (Heroicons/Lucide)") lines.append("- [ ] `cursor-pointer` on all clickable elements") lines.append("- [ ] Hover states with smooth transitions (150-300ms)") lines.append("- [ ] Light mode: text contrast 4.5:1 minimum") lines.append("- [ ] Focus states visible for keyboard navigation") lines.append("- [ ] `prefers-reduced-motion` respected") lines.append("- [ ] Responsive: 375px, 768px, 1024px, 1440px") lines.append("- [ ] No content hidden behind fixed navbars") lines.append("- [ ] No horizontal scroll on mobile") lines.append("") return "\n".join(lines) def format_page_override_md(design_system: dict, page_name: str, page_query: str = None) -> str: """Format a page-specific override file with intelligent AI-generated content.""" project = design_system.get("project_name", "PROJECT") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") page_title = page_name.replace("-", " ").replace("_", " ").title() # Detect page type and generate intelligent overrides page_overrides = _generate_intelligent_overrides(page_name, page_query, design_system) lines = [] lines.append(f"# {page_title} Page Overrides") lines.append("") lines.append(f"> **PROJECT:** {project}") lines.append(f"> **Generated:** {timestamp}") lines.append(f"> **Page Type:** {page_overrides.get('page_type', 'General')}") lines.append("") lines.append("> ⚠️ **IMPORTANT:** Rules in this file **override** the Master file (`design-system/MASTER.md`).") lines.append("> Only deviations from the Master are documented here. For all other rules, refer to the Master.") lines.append("") lines.append("---") lines.append("") # Page-specific rules with actual content lines.append("## Page-Specific Rules") lines.append("") # Layout Overrides lines.append("### Layout Overrides") lines.append("") layout = page_overrides.get("layout", {}) if layout: for key, value in layout.items(): lines.append(f"- **{key}:** {value}") else: lines.append("- No overrides — use Master layout") lines.append("") # Spacing Overrides lines.append("### Spacing Overrides") lines.append("") spacing = page_overrides.get("spacing", {}) if spacing: for key, value in spacing.items(): lines.append(f"- **{key}:** {value}") else: lines.append("- No overrides — use Master spacing") lines.append("") # Typography Overrides lines.append("### Typography Overrides") lines.append("") typography = page_overrides.get("typography", {}) if typography: for key, value in typography.items(): lines.append(f"- **{key}:** {value}") else: lines.append("- No overrides — use Master typography") lines.append("") # Color Overrides lines.append("### Color Overrides") lines.append("") colors = page_overrides.get("colors", {}) if colors: for key, value in colors.items(): lines.append(f"- **{key}:** {value}") else: lines.append("- No overrides — use Master colors") lines.append("") # Component Overrides lines.append("### Component Overrides") lines.append("") components = page_overrides.get("components", []) if components: for comp in components: lines.append(f"- {comp}") else: lines.append("- No overrides — use Master component specs") lines.append("") # Page-Specific Components lines.append("---") lines.append("") lines.append("## Page-Specific Components") lines.append("") unique_components = page_overrides.get("unique_components", []) if unique_components: for comp in unique_components: lines.append(f"- {comp}") else: lines.append("- No unique components for this page") lines.append("") # Recommendations lines.append("---") lines.append("") lines.append("## Recommendations") lines.append("") recommendations = page_overrides.get("recommendations", []) if recommendations: for rec in recommendations: lines.append(f"- {rec}") lines.append("") return "\n".join(lines) def _generate_intelligent_overrides(page_name: str, page_query: str, design_system: dict) -> dict: """ Generate intelligent overrides based on page type using layered search. Uses the existing search infrastructure to find relevant style, UX, and layout data instead of hardcoded page types. """ from core import search page_lower = page_name.lower() query_lower = (page_query or "").lower() combined_context = f"{page_lower} {query_lower}" # Search across multiple domains for page-specific guidance style_search = search(combined_context, "style", max_results=1) ux_search = search(combined_context, "ux", max_results=3) landing_search = search(combined_context, "landing", max_results=1) # Extract results from search response style_results = style_search.get("results", []) ux_results = ux_search.get("results", []) landing_results = landing_search.get("results", []) # Detect page type from search results or context page_type = _detect_page_type(combined_context, style_results) # Build overrides from search results layout = {} spacing = {} typography = {} colors = {} components = [] unique_components = [] recommendations = [] # Extract style-based overrides if style_results: style = style_results[0] style_name = style.get("Style Category", "") keywords = style.get("Keywords", "") best_for = style.get("Best For", "") effects = style.get("Effects & Animation", "") # Infer layout from style keywords if any(kw in keywords.lower() for kw in ["data", "dense", "dashboard", "grid"]): layout["Max Width"] = "1400px or full-width" layout["Grid"] = "12-column grid for data flexibility" spacing["Content Density"] = "High — optimize for information display" elif any(kw in keywords.lower() for kw in ["minimal", "simple", "clean", "single"]): layout["Max Width"] = "800px (narrow, focused)" layout["Layout"] = "Single column, centered" spacing["Content Density"] = "Low — focus on clarity" else: layout["Max Width"] = "1200px (standard)" layout["Layout"] = "Full-width sections, centered content" if effects: recommendations.append(f"Effects: {effects}") # Extract UX guidelines as recommendations for ux in ux_results: category = ux.get("Category", "") do_text = ux.get("Do", "") dont_text = ux.get("Don't", "") if do_text: recommendations.append(f"{category}: {do_text}") if dont_text: components.append(f"Avoid: {dont_text}") # Extract landing pattern info for section structure if landing_results: landing = landing_results[0] sections = landing.get("Section Order", "") cta_placement = landing.get("Primary CTA Placement", "") color_strategy = landing.get("Color Strategy", "") if sections: layout["Sections"] = sections if cta_placement: recommendations.append(f"CTA Placement: {cta_placement}") if color_strategy: colors["Strategy"] = color_strategy # Add page-type specific defaults if no search results if not layout: layout["Max Width"] = "1200px" layout["Layout"] = "Responsive grid" if not recommendations: recommendations = [ "Refer to MASTER.md for all design rules", "Add specific overrides as needed for this page" ] return { "page_type": page_type, "layout": layout, "spacing": spacing, "typography": typography, "colors": colors, "components": components, "unique_components": unique_components, "recommendations": recommendations } def _detect_page_type(context: str, style_results: list) -> str: """Detect page type from context and search results.""" context_lower = context.lower() # Check for common page type patterns page_patterns = [ (["dashboard", "admin", "analytics", "data", "metrics", "stats", "monitor", "overview"], "Dashboard / Data View"), (["checkout", "payment", "cart", "purchase", "order", "billing"], "Checkout / Payment"), (["settings", "profile", "account", "preferences", "config"], "Settings / Profile"), (["landing", "marketing", "homepage", "hero", "home", "promo"], "Landing / Marketing"), (["login", "signin", "signup", "register", "auth", "password"], "Authentication"), (["pricing", "plans", "subscription", "tiers", "packages"], "Pricing / Plans"), (["blog", "article", "post", "news", "content", "story"], "Blog / Article"), (["product", "item", "detail", "pdp", "shop", "store"], "Product Detail"), (["search", "results", "browse", "filter", "catalog", "list"], "Search Results"), (["empty", "404", "error", "not found", "zero"], "Empty State"), ] for keywords, page_type in page_patterns: if any(kw in context_lower for kw in keywords): return page_type # Fallback: try to infer from style results if style_results: style_name = style_results[0].get("Style Category", "").lower() best_for = style_results[0].get("Best For", "").lower() if "dashboard" in best_for or "data" in best_for: return "Dashboard / Data View" elif "landing" in best_for or "marketing" in best_for: return "Landing / Marketing" return "General" # ============ CLI SUPPORT ============ if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="Generate Design System") parser.add_argument("query", help="Search query (e.g., 'SaaS dashboard')") parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name") parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format") args = parser.parse_args() result = generate_design_system(args.query, args.project_name, args.format) print(result)
未来鸟
2026年7月27日 11:16
转发
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
分享
链接
类型
密码
更新密码
有效期
Markdown文件
Word文件
PDF文档(打印)
AI