mirror of
https://github.com/nextlevelbuilder/ui-ux-pro-max-skill.git
synced 2026-07-07 14:38:49 +08:00
PR #296 (feat/emil-motion-principles) independently registers a "motion" domain key in CSV_CONFIG/detect_domain for motion-principles.csv (37 design-principle rows). Both PRs adding the same dict key would cause one to silently overwrite the other's domain registration if merged independently, per the automated review on this PR. The two domains are complementary, not duplicate (design principles vs. ready-to-use GSAP code snippets), so this renames this PR's domain from "motion" to "gsap" - a more precise name given every row is GSAP-specific implementation code. The --motion CLI dial and its "Subtle/Standard/ Complex" tiers are unaffected (unrelated to the domain key; only the `--domain gsap` search endpoint and its internal lookup changed). No regressions: --design-system output with no dials set remains byte-identical to before this feature. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
128 lines
6.5 KiB
Python
128 lines
6.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
UI/UX Pro Max Search - BM25 search engine for UI/UX style guides
|
|
Usage: python search.py "<query>" [--domain <domain>] [--stack <stack>] [--max-results 3]
|
|
python search.py "<query>" --design-system [-p "Project Name"]
|
|
python search.py "<query>" --design-system --persist [-p "Project Name"] [--page "dashboard"]
|
|
python search.py "<query>" --design-system --variance 8 --motion 9 --density 7
|
|
|
|
Domains: style, prompt, color, chart, landing, product, ux, typography, google-fonts, gsap
|
|
Stacks: react, nextjs, vue, svelte, astro, swiftui, react-native, flutter, nuxtjs, nuxt-ui, html-tailwind, shadcn, jetpack-compose, threejs, angular, laravel, javafx, wpf, winui, avalonia, uno, uwp
|
|
|
|
Design dials (1-10, only with --design-system):
|
|
--variance DESIGN_VARIANCE: 1=centered/minimal, 10=bold/asymmetric
|
|
--motion MOTION_INTENSITY: 1=subtle, 10=complex; attaches a GSAP snippet from motion.csv
|
|
--density VISUAL_DENSITY: 1=spacious, 10=dense/dashboard; overrides the spacing scale
|
|
|
|
Persistence (Master + Overrides pattern):
|
|
--persist Save design system to design-system/MASTER.md
|
|
--page Also create a page-specific override file in design-system/pages/
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
import io
|
|
from core import CSV_CONFIG, AVAILABLE_STACKS, MAX_RESULTS, search, search_stack
|
|
from design_system import generate_design_system, persist_design_system
|
|
|
|
# Force UTF-8 for stdout/stderr to handle emojis on Windows (cp1252 default)
|
|
if sys.stdout.encoding and sys.stdout.encoding.lower() != 'utf-8':
|
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
|
if sys.stderr.encoding and sys.stderr.encoding.lower() != 'utf-8':
|
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')
|
|
|
|
|
|
def format_output(result):
|
|
"""Format results for Claude consumption (token-optimized)"""
|
|
if "error" in result:
|
|
return f"Error: {result['error']}"
|
|
|
|
output = []
|
|
if result.get("stack"):
|
|
output.append(f"## UI Pro Max Stack Guidelines")
|
|
output.append(f"**Stack:** {result['stack']} | **Query:** {result['query']}")
|
|
else:
|
|
output.append(f"## UI Pro Max Search Results")
|
|
output.append(f"**Domain:** {result['domain']} | **Query:** {result['query']}")
|
|
output.append(f"**Source:** {result['file']} | **Found:** {result['count']} results\n")
|
|
|
|
for i, row in enumerate(result['results'], 1):
|
|
output.append(f"### Result {i}")
|
|
for key, value in row.items():
|
|
value_str = str(value)
|
|
if len(value_str) > 300:
|
|
value_str = value_str[:300] + "..."
|
|
output.append(f"- **{key}:** {value_str}")
|
|
output.append("")
|
|
|
|
return "\n".join(output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="UI Pro Max Search")
|
|
parser.add_argument("query", help="Search query")
|
|
parser.add_argument("--domain", "-d", choices=list(CSV_CONFIG.keys()), help="Search domain")
|
|
parser.add_argument("--stack", "-s", choices=AVAILABLE_STACKS, help=f"Stack-specific search. Available: {', '.join(AVAILABLE_STACKS)}")
|
|
parser.add_argument("--max-results", "-n", type=int, default=MAX_RESULTS, help="Max results (default: 3)")
|
|
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
|
# Design system generation
|
|
parser.add_argument("--design-system", "-ds", action="store_true", help="Generate complete design system recommendation")
|
|
parser.add_argument("--project-name", "-p", type=str, default=None, help="Project name for design system output")
|
|
parser.add_argument("--format", "-f", choices=["ascii", "markdown"], default="ascii", help="Output format for design system")
|
|
# Persistence (Master + Overrides pattern)
|
|
parser.add_argument("--persist", action="store_true", help="Save design system to design-system/MASTER.md (creates hierarchical structure)")
|
|
parser.add_argument("--page", type=str, default=None, help="Create page-specific override file in design-system/pages/")
|
|
parser.add_argument("--output-dir", "-o", type=str, default=None, help="Output directory for persisted files (default: current directory)")
|
|
# Design dials (1-10), only applied with --design-system
|
|
parser.add_argument("--variance", type=int, choices=range(1, 11), metavar="1-10", help="DESIGN_VARIANCE dial: 1=centered/minimal, 10=bold/asymmetric (only with --design-system)")
|
|
parser.add_argument("--motion", type=int, choices=range(1, 11), metavar="1-10", help="MOTION_INTENSITY dial: 1=subtle, 10=complex; pulls a matching GSAP snippet from motion.csv (only with --design-system)")
|
|
parser.add_argument("--density", type=int, choices=range(1, 11), metavar="1-10", help="VISUAL_DENSITY dial: 1=spacious, 10=dense/dashboard; overrides the spacing scale (only with --design-system)")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Design system takes priority
|
|
if args.design_system:
|
|
result = generate_design_system(
|
|
args.query,
|
|
args.project_name,
|
|
args.format,
|
|
persist=args.persist,
|
|
page=args.page,
|
|
output_dir=args.output_dir,
|
|
variance=args.variance,
|
|
motion=args.motion,
|
|
density=args.density
|
|
)
|
|
print(result)
|
|
|
|
# Print persistence confirmation
|
|
if args.persist:
|
|
project_slug = (args.project_name or args.query).lower().replace(' ', '-')
|
|
print("\n" + "=" * 60)
|
|
print(f"✅ Design system persisted to design-system/{project_slug}/")
|
|
print(f" 📄 design-system/{project_slug}/MASTER.md (Global Source of Truth)")
|
|
if args.page:
|
|
page_filename = args.page.lower().replace(' ', '-')
|
|
print(f" 📄 design-system/{project_slug}/pages/{page_filename}.md (Page Overrides)")
|
|
print("")
|
|
print(f"📖 Usage: When building a page, check design-system/{project_slug}/pages/[page].md first.")
|
|
print(f" If exists, its rules override MASTER.md. Otherwise, use MASTER.md.")
|
|
print("=" * 60)
|
|
# Stack search
|
|
elif args.stack:
|
|
result = search_stack(args.query, args.stack, args.max_results)
|
|
if args.json:
|
|
import json
|
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
else:
|
|
print(format_output(result))
|
|
# Domain search
|
|
else:
|
|
result = search(args.query, args.domain, args.max_results)
|
|
if args.json:
|
|
import json
|
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
|
else:
|
|
print(format_output(result))
|