Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66a376c752 | ||
|
|
765b0bb936 | ||
|
|
2e7acbf50f | ||
|
|
fc9956c648 | ||
|
|
e916556576 | ||
|
|
f9b65919cf |
@@ -201,6 +201,7 @@ Before delivering UI code, verify these items:
|
|||||||
- [ ] All icons from consistent icon set (Heroicons/Lucide)
|
- [ ] All icons from consistent icon set (Heroicons/Lucide)
|
||||||
- [ ] Brand logos are correct (verified from Simple Icons)
|
- [ ] Brand logos are correct (verified from Simple Icons)
|
||||||
- [ ] Hover states don't cause layout shift
|
- [ ] Hover states don't cause layout shift
|
||||||
|
- [ ] Use theme colors directly (bg-primary) not var() wrapper
|
||||||
|
|
||||||
### Interaction
|
### Interaction
|
||||||
- [ ] All clickable elements have `cursor-pointer`
|
- [ ] All clickable elements have `cursor-pointer`
|
||||||
|
|||||||
@@ -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
|
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
|
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
|
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
|
||||||
|
|||||||
|
@@ -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
|
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
|
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
|
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
|
||||||
|
|||||||
|
@@ -56,3 +56,12 @@ When modifying files, keep all agent workflows in sync:
|
|||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Python 3.x (no external dependencies required)
|
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`
|
||||||
|
|||||||
49
README.md
49
README.md
@@ -75,42 +75,23 @@ sudo apt update && sudo apt install python3
|
|||||||
winget install Python.Python.3.12
|
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
|
## 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
|
### Example Prompts
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uipro-cli",
|
"name": "uipro-cli",
|
||||||
"version": "1.0.0",
|
"version": "1.0.3",
|
||||||
"description": "CLI to install UI/UX Pro Max skill for AI coding assistants",
|
"description": "CLI to install UI/UX Pro Max skill for AI coding assistants",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const program = new Command();
|
|||||||
program
|
program
|
||||||
.name('uipro')
|
.name('uipro')
|
||||||
.description('CLI to install UI/UX Pro Max skill for AI coding assistants')
|
.description('CLI to install UI/UX Pro Max skill for AI coding assistants')
|
||||||
.version('1.0.0');
|
.version('1.0.3');
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('init')
|
.command('init')
|
||||||
|
|||||||
@@ -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 { join } from 'node:path';
|
||||||
|
import { exec } from 'node:child_process';
|
||||||
|
import { promisify } from 'node:util';
|
||||||
import type { AIType } from '../types/index.js';
|
import type { AIType } from '../types/index.js';
|
||||||
import { AI_FOLDERS } from '../types/index.js';
|
import { AI_FOLDERS } from '../types/index.js';
|
||||||
|
|
||||||
export async function extractZip(zipPath: string, destDir: string): Promise<void> {
|
const execAsync = promisify(exec);
|
||||||
const proc = Bun.spawn(['unzip', '-o', zipPath, '-d', destDir], {
|
|
||||||
stdout: 'pipe',
|
|
||||||
stderr: 'pipe',
|
|
||||||
});
|
|
||||||
|
|
||||||
const exitCode = await proc.exited;
|
export async function extractZip(zipPath: string, destDir: string): Promise<void> {
|
||||||
if (exitCode !== 0) {
|
try {
|
||||||
throw new Error(`Failed to extract zip: exit code ${exitCode}`);
|
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);
|
const targetPath = join(targetDir, folder);
|
||||||
|
|
||||||
// Check if source folder exists
|
// Check if source folder exists
|
||||||
const sourceExists = await Bun.file(sourcePath).exists().catch(() => false);
|
const sourceExists = await exists(sourcePath);
|
||||||
if (!sourceExists) {
|
if (!sourceExists) {
|
||||||
// Try checking if it's a directory
|
continue;
|
||||||
try {
|
|
||||||
const proc = Bun.spawn(['test', '-d', sourcePath]);
|
|
||||||
await proc.exited;
|
|
||||||
} catch {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create target directory if needed
|
// Create target directory if needed
|
||||||
await mkdir(targetPath, { recursive: true });
|
await mkdir(targetPath, { recursive: true });
|
||||||
|
|
||||||
// Copy using cp -r
|
// Copy recursively
|
||||||
const proc = Bun.spawn(['cp', '-r', `${sourcePath}/.`, targetPath], {
|
try {
|
||||||
stdout: 'pipe',
|
await cp(sourcePath, targetPath, { recursive: true });
|
||||||
stderr: 'pipe',
|
|
||||||
});
|
|
||||||
|
|
||||||
const exitCode = await proc.exited;
|
|
||||||
if (exitCode === 0) {
|
|
||||||
copiedFolders.push(folder);
|
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> {
|
export async function cleanup(tempDir: string): Promise<void> {
|
||||||
const proc = Bun.spawn(['rm', '-rf', tempDir], {
|
try {
|
||||||
stdout: 'pipe',
|
await rm(tempDir, { recursive: true, force: true });
|
||||||
stderr: 'pipe',
|
} catch {
|
||||||
});
|
// Ignore cleanup errors
|
||||||
await proc.exited;
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { writeFile } from 'node:fs/promises';
|
||||||
import type { Release } from '../types/index.js';
|
import type { Release } from '../types/index.js';
|
||||||
|
|
||||||
const REPO_OWNER = 'nextlevelbuilder';
|
const REPO_OWNER = 'nextlevelbuilder';
|
||||||
@@ -50,7 +51,7 @@ export async function downloadRelease(url: string, dest: string): Promise<void>
|
|||||||
}
|
}
|
||||||
|
|
||||||
const buffer = await response.arrayBuffer();
|
const buffer = await response.arrayBuffer();
|
||||||
await Bun.write(dest, buffer);
|
await writeFile(dest, Buffer.from(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAssetUrl(release: Release): string | null {
|
export function getAssetUrl(release: Release): string | null {
|
||||||
|
|||||||
Reference in New Issue
Block a user