6 Commits

Author SHA1 Message Date
Viet Tran
66a376c752 fix: add Tailwind theme color variables guideline (#10)
- Add guideline to use bg-primary instead of bg-[var(--color-primary)]
- Add checklist item in SKILL.md Pre-Delivery Checklist
- Sync html-tailwind.csv to .shared folder

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:31:18 +07:00
Viet Tran
765b0bb936 docs: add git workflow rules to CLAUDE.md (#9)
- Never push directly to main
- Always create branch and PR

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:21:41 +07:00
Viet Tran
2e7acbf50f fix: add Windows compatibility for zip extraction and file copy
- Use PowerShell Expand-Archive on Windows instead of unzip
- Use xcopy on Windows instead of cp -r in shell fallback
- Bump version to 1.0.3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 10:18:18 +07:00
Viet Tran
fc9956c648 docs: remove project structure section from README
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 19:34:55 +07:00
Viet Tran
e916556576 docs: add platform-specific usage instructions for slash commands
- Claude Code: skill activates automatically
- Cursor/Windsurf/Antigravity: use /ui-ux-pro-max [prompt]

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 19:31:31 +07:00
Viet Tran
f9b65919cf fix: replace Bun-specific APIs with Node.js APIs for npm compatibility
- Replace Bun.spawn with exec from child_process in extract.ts
- Replace Bun.file().exists() with access from fs/promises
- Replace Bun.write with writeFile from fs/promises in github.ts
- Add cp and rm from fs/promises for file operations
- Bump version to 1.0.2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 19:23:28 +07:00
9 changed files with 76 additions and 67 deletions

View File

@@ -201,6 +201,7 @@ Before delivering UI code, verify these items:
- [ ] All icons from consistent icon set (Heroicons/Lucide)
- [ ] Brand logos are correct (verified from Simple Icons)
- [ ] Hover states don't cause layout shift
- [ ] Use theme colors directly (bg-primary) not var() wrapper
### Interaction
- [ ] All clickable elements have `cursor-pointer`

View File

@@ -49,3 +49,4 @@ No,Category,Guideline,Description,Do,Don't,Code Good,Code Bad,Severity,Docs URL
48,Layout,Container Queries,Use @container for component-based responsiveness,Use @container and @lg: etc.,Media queries for component internals,@container @lg:grid-cols-2,@media (min-width: ...) inside component,Medium,https://github.com/tailwindlabs/tailwindcss-container-queries
49,Interactivity,Group and Peer,Style based on parent/sibling state,group-hover peer-checked,JS for simple state interactions,group-hover:text-blue-500,onMouseEnter={() => setHover(true)},Low,https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
50,Customization,Arbitrary Values,Use [] for one-off values,w-[350px] for specific needs,Creating config for single use,top-[117px] (if strictly needed),style={{ top: '117px' }},Low,https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
51,Colors,Theme color variables,Define colors in Tailwind theme and use directly,bg-primary text-success border-cta,bg-[var(--color-primary)] text-[var(--color-success)],bg-primary,bg-[var(--color-primary)],Medium,https://tailwindcss.com/docs/customizing-colors
1 No Category Guideline Description Do Don't Code Good Code Bad Severity Docs URL
49 48 Layout Container Queries Use @container for component-based responsiveness Use @container and @lg: etc. Media queries for component internals @container @lg:grid-cols-2 @media (min-width: ...) inside component Medium https://github.com/tailwindlabs/tailwindcss-container-queries
50 49 Interactivity Group and Peer Style based on parent/sibling state group-hover peer-checked JS for simple state interactions group-hover:text-blue-500 onMouseEnter={() => setHover(true)} Low https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
51 50 Customization Arbitrary Values Use [] for one-off values w-[350px] for specific needs Creating config for single use top-[117px] (if strictly needed) style={{ top: '117px' }} Low https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
52 51 Colors Theme color variables Define colors in Tailwind theme and use directly bg-primary text-success border-cta bg-[var(--color-primary)] text-[var(--color-success)] bg-primary bg-[var(--color-primary)] Medium https://tailwindcss.com/docs/customizing-colors

View File

@@ -49,3 +49,4 @@ No,Category,Guideline,Description,Do,Don't,Code Good,Code Bad,Severity,Docs URL
48,Layout,Container Queries,Use @container for component-based responsiveness,Use @container and @lg: etc.,Media queries for component internals,@container @lg:grid-cols-2,@media (min-width: ...) inside component,Medium,https://github.com/tailwindlabs/tailwindcss-container-queries
49,Interactivity,Group and Peer,Style based on parent/sibling state,group-hover peer-checked,JS for simple state interactions,group-hover:text-blue-500,onMouseEnter={() => setHover(true)},Low,https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
50,Customization,Arbitrary Values,Use [] for one-off values,w-[350px] for specific needs,Creating config for single use,top-[117px] (if strictly needed),style={{ top: '117px' }},Low,https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
51,Colors,Theme color variables,Define colors in Tailwind theme and use directly,bg-primary text-success border-cta,bg-[var(--color-primary)] text-[var(--color-success)],bg-primary,bg-[var(--color-primary)],Medium,https://tailwindcss.com/docs/customizing-colors
1 No Category Guideline Description Do Don't Code Good Code Bad Severity Docs URL
49 48 Layout Container Queries Use @container for component-based responsiveness Use @container and @lg: etc. Media queries for component internals @container @lg:grid-cols-2 @media (min-width: ...) inside component Medium https://github.com/tailwindlabs/tailwindcss-container-queries
50 49 Interactivity Group and Peer Style based on parent/sibling state group-hover peer-checked JS for simple state interactions group-hover:text-blue-500 onMouseEnter={() => setHover(true)} Low https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
51 50 Customization Arbitrary Values Use [] for one-off values w-[350px] for specific needs Creating config for single use top-[117px] (if strictly needed) style={{ top: '117px' }} Low https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
52 51 Colors Theme color variables Define colors in Tailwind theme and use directly bg-primary text-success border-cta bg-[var(--color-primary)] text-[var(--color-success)] bg-primary bg-[var(--color-primary)] Medium https://tailwindcss.com/docs/customizing-colors

View File

@@ -56,3 +56,12 @@ When modifying files, keep all agent workflows in sync:
## Prerequisites
Python 3.x (no external dependencies required)
## Git Workflow
Never push directly to `main`. Always:
1. Create a new branch: `git checkout -b feat/... ` or `fix/...`
2. Commit changes
3. Push branch: `git push -u origin <branch>`
4. Create PR: `gh pr create`

View File

@@ -75,42 +75,23 @@ sudo apt update && sudo apt install python3
winget install Python.Python.3.12
```
## Project Structure
```
ui-ux-pro-max-skill/
├── cli/ # CLI installer (uipro-cli)
│ ├── package.json
│ └── src/
├── .claude/skills/ui-ux-pro-max/ # Claude Code skill
│ ├── SKILL.md
│ ├── scripts/
│ │ ├── search.py
│ │ └── core.py
│ └── data/
│ ├── styles.csv
│ ├── colors.csv
│ ├── typography.csv
│ ├── charts.csv
│ ├── products.csv
│ ├── landing.csv
│ ├── ux-guidelines.csv
│ ├── prompts.csv
│ └── stacks/
├── .cursor/commands/ # Cursor command
│ └── ui-ux-pro-max.md
├── .windsurf/workflows/ # Windsurf workflow
│ └── ui-ux-pro-max.md
├── .agent/workflows/ # Antigravity workflow
│ └── ui-ux-pro-max.md
└── .shared/ui-ux-pro-max/ # Shared scripts & data
├── scripts/
└── data/
```
## Usage
After installation, just chat with your AI assistant naturally. The skill will automatically activate when you request UI/UX work.
### Claude Code
The skill activates automatically when you request UI/UX work. Just chat naturally:
```
Build a landing page for my SaaS product
```
### Cursor / Windsurf / Antigravity
Use the slash command to invoke the skill:
```
/ui-ux-pro-max Build a landing page for my SaaS product
```
### Example Prompts

View File

@@ -1,6 +1,6 @@
{
"name": "uipro-cli",
"version": "1.0.0",
"version": "1.0.3",
"description": "CLI to install UI/UX Pro Max skill for AI coding assistants",
"type": "module",
"bin": {

View File

@@ -12,7 +12,7 @@ const program = new Command();
program
.name('uipro')
.description('CLI to install UI/UX Pro Max skill for AI coding assistants')
.version('1.0.0');
.version('1.0.3');
program
.command('init')

View File

@@ -1,17 +1,31 @@
import { mkdir } from 'node:fs/promises';
import { mkdir, rm, access, cp } from 'node:fs/promises';
import { join } from 'node:path';
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
import type { AIType } from '../types/index.js';
import { AI_FOLDERS } from '../types/index.js';
export async function extractZip(zipPath: string, destDir: string): Promise<void> {
const proc = Bun.spawn(['unzip', '-o', zipPath, '-d', destDir], {
stdout: 'pipe',
stderr: 'pipe',
});
const execAsync = promisify(exec);
const exitCode = await proc.exited;
if (exitCode !== 0) {
throw new Error(`Failed to extract zip: exit code ${exitCode}`);
export async function extractZip(zipPath: string, destDir: string): Promise<void> {
try {
const isWindows = process.platform === 'win32';
if (isWindows) {
await execAsync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${destDir}' -Force"`);
} else {
await execAsync(`unzip -o "${zipPath}" -d "${destDir}"`);
}
} catch (error) {
throw new Error(`Failed to extract zip: ${error}`);
}
}
async function exists(path: string): Promise<boolean> {
try {
await access(path);
return true;
} catch {
return false;
}
}
@@ -34,29 +48,30 @@ export async function copyFolders(
const targetPath = join(targetDir, folder);
// Check if source folder exists
const sourceExists = await Bun.file(sourcePath).exists().catch(() => false);
const sourceExists = await exists(sourcePath);
if (!sourceExists) {
// Try checking if it's a directory
try {
const proc = Bun.spawn(['test', '-d', sourcePath]);
await proc.exited;
} catch {
continue;
}
}
// Create target directory if needed
await mkdir(targetPath, { recursive: true });
// Copy using cp -r
const proc = Bun.spawn(['cp', '-r', `${sourcePath}/.`, targetPath], {
stdout: 'pipe',
stderr: 'pipe',
});
const exitCode = await proc.exited;
if (exitCode === 0) {
// Copy recursively
try {
await cp(sourcePath, targetPath, { recursive: true });
copiedFolders.push(folder);
} catch {
// Try shell fallback for older Node versions
try {
if (process.platform === 'win32') {
await execAsync(`xcopy "${sourcePath}" "${targetPath}" /E /I /Y`);
} else {
await execAsync(`cp -r "${sourcePath}/." "${targetPath}"`);
}
copiedFolders.push(folder);
} catch {
// Skip if copy fails
}
}
}
@@ -64,9 +79,9 @@ export async function copyFolders(
}
export async function cleanup(tempDir: string): Promise<void> {
const proc = Bun.spawn(['rm', '-rf', tempDir], {
stdout: 'pipe',
stderr: 'pipe',
});
await proc.exited;
try {
await rm(tempDir, { recursive: true, force: true });
} catch {
// Ignore cleanup errors
}
}

View File

@@ -1,3 +1,4 @@
import { writeFile } from 'node:fs/promises';
import type { Release } from '../types/index.js';
const REPO_OWNER = 'nextlevelbuilder';
@@ -50,7 +51,7 @@ export async function downloadRelease(url: string, dest: string): Promise<void>
}
const buffer = await response.arrayBuffer();
await Bun.write(dest, buffer);
await writeFile(dest, Buffer.from(buffer));
}
export function getAssetUrl(release: Release): string | null {