From bd49f4fe3b6db8c3f2b7ead499316e9706044d9d Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Sat, 31 Jan 2026 19:55:54 +0700 Subject: [PATCH] feat: Add build system for external component references and expand documentation on Atomic Design principles and modular architecture. --- .agent/skills/pencil-design/SKILL.md | 718 ++++++++++++++++++++++++++- 1 file changed, 693 insertions(+), 25 deletions(-) diff --git a/.agent/skills/pencil-design/SKILL.md b/.agent/skills/pencil-design/SKILL.md index 8d240a08..52060321 100644 --- a/.agent/skills/pencil-design/SKILL.md +++ b/.agent/skills/pencil-design/SKILL.md @@ -1,11 +1,11 @@ --- name: pencil-design -description: Pencil UI/UX design tool workflows và file format. Use for reading .pen files, extracting design content, converting designs to HTML/CSS/React/Blazor code, và understanding component systems. +description: Pencil UI/UX design tool workflows, file format parsing, component systems, và Atomic Design Hierarchy cho enterprise UI Kits. Use for reading .pen files, extracting content, converting to code (HTML/CSS/React/Blazor), modular design workflows, và organizing large-scale design systems. compatibility: "Pencil 2.6+, JSON parsing" metadata: author: Velik Ho - version: "1.0" - references: "pencil.evolus.vn, Pencil GitHub" + version: "2.0" + references: "pencil.evolus.vn, Pencil GitHub, Atomic Design methodology" --- # Pencil Design Tool / Công cụ thiết kế Pencil @@ -44,6 +44,7 @@ metadata: | `ellipse` | Circle/Ellipse | `width`, `height`, `fill` | | `icon_font` | Icon (Lucide) | `iconFontName`, `iconFontFamily`, `fill` | | `ref` | Component instance | `ref` (ID), `descendants` (overrides) | +| `component_ref` | External component reference | `component` (path), `overrides` (property overrides) | ### 2.3 Layout Properties @@ -112,6 +113,7 @@ Components có `reusable: true` có thể được tham chiếu lại: ### 4.2 Component Instances (Refs) +**Internal refs (same file):** ```json { "type": "ref", @@ -125,9 +127,116 @@ Components có `reusable: true` có thể được tham chiếu lại: } ``` -## 5. Workflows +**External refs (cross-file, using build system):** +```json +{ + "type": "component_ref", + "component": "ui-kit#Button/Primary", // Library#ComponentPath + "name": "myButton", + "overrides": { // Override properties + "q7oNn": { + "content": "Click Me" + } + }, + "x": 100, + "y": 200 +} +``` -### 5.1 Đọc và Phân tích Design +> [!NOTE] +> `component_ref` is a custom type processed by the build system. It will be converted to a proper `ref` type during build, with the component injected into the file. + +## 5. Build System + +### 5.1 Configuration File + +Create `pencil.config.json` in project root: +```json +{ + "version": "1.0", + "sourceDir": "src", + "buildDir": "build", + "componentLibrary": "src/components/ui-kit.pen", + "buildOptions": { + "minify": false, + "validateAfterBuild": true, + "preserveComments": true + } +} +``` + +### 5.2 Build Script + +The build system (`scripts/build.py`) supports two modes: + +#### Monolithic Build ⭐ (Recommended) +Merges all pages + component library into one file: +```bash +python3 scripts/build.py --monolithic +# or +python3 scripts/build.py -m + +# Custom output +python3 scripts/build.py -m --output myDesign.pen +``` + +**Output:** +- File: `tPOS.pen` (project root) +- Contains: All pages + component library as separate frames +- Size: ~326KB +- Use case: Opening complete design, sharing, archiving + +#### Standard Build +Builds individual pages with component injection: +```bash +python3 scripts/build.py +``` + +**Output:** +- Directory: `build/` +- Files: Separate `.pen` files with injected components +- Use case: Development workflow, testing component refs + +### 5.3 Build Process + +**What the build script does:** +1. Loads component library (`ui-kit.pen`) +2. Extracts all reusable components and design variables +3. Finds all `component_ref` types in page files +4. Resolves component paths (e.g., `ui-kit#Button/Primary`) +5. Injects component definitions into page files +6. Converts `component_ref` → `ref` with proper IDs +7. Validates output structure + +**Example transformation:** +```json +// Before build (in source) +{ + "type": "component_ref", + "component": "ui-kit#Button/Primary" +} + +// After build (in output) +// 1. Component injected at top of children array +{ + "type": "frame", + "id": "abc123", + "name": "Button/Primary", + "reusable": true, + "children": [...] +} + +// 2. Reference converted +{ + "type": "ref", + "ref": "abc123", + "descendants": {...} +} +``` + +## 6. Workflows + +### 6.1 Đọc và Phân tích Design ```markdown 1. Mở file .pen bằng view_file tool @@ -137,7 +246,7 @@ Components có `reusable: true` có thể được tham chiếu lại: 5. List design tokens từ "variables" ``` -### 5.2 Extract Content +### 6.2 Extract Content ```markdown 1. Tìm tất cả elements có type "text" @@ -146,7 +255,7 @@ Components có `reusable: true` có thể được tham chiếu lại: 4. Export dạng structured text hoặc JSON ``` -### 5.3 Design to Code Conversion +### 6.3 Design to Code Conversion **Step 1: Analyze Structure** ```markdown @@ -173,7 +282,7 @@ border-radius: 10px /* cornerRadius: 10 */ background: linear-gradient /* fill.type: "gradient" */ ``` -### 5.4 Design System Extraction +### 6.4 Design System Extraction ```markdown 1. Extract all "variables" as CSS custom properties @@ -193,9 +302,30 @@ background: linear-gradient /* fill.type: "gradient" */ } ``` -## 6. Common Patterns +### 6.5 Build and Deploy Workflow -### 6.1 Page Structure +**Development cycle:** +```markdown +1. Design in modular files: + - Edit components in `src/components/ui-kit.pen` + - Edit pages in `src/pages/*.pen` + - Use `component_ref` to reference components + +2. Build for testing: + python3 scripts/build.py # Standard build + # Open files in build/ to test + +3. Build for production: + python3 scripts/build.py -m # Monolithic + # Share tPOS.pen with team/clients + +4. Convert to code: + # Use agent to convert tPOS.pen to HTML/CSS/React/Blazor +``` + +## 7. Common Patterns + +### 7.1 Page Structure ``` Page Frame @@ -207,8 +337,9 @@ Page Frame └── Footer ``` -### 6.2 Component Naming Convention +### 7.2 Component Naming Convention +**Traditional (Simple Projects):** ``` Component/{Category}/{Variant} - Component/Button/Primary @@ -217,7 +348,136 @@ Component/{Category}/{Variant} - Component/Card/Pricing ``` -### 6.3 Modular Design Architecture (Hybrid Approach) +**Atomic Design (Enterprise):** +``` +{AtomicLevel}/{Component}/{Variant}/{State} + +Atoms: +- Atom/Button/Primary/Default +- Atom/Button/Primary/Hover +- Atom/Button/Primary/Disabled +- Atom/Badge/Section/Default +- Atom/Input/Text/Default +- Atom/Input/Text/Error + +Molecules: +- Molecule/FormField/Text/Default +- Molecule/FormField/Text/WithError +- Molecule/SearchBar/Default +- Molecule/CardHeader/WithIcon + +Organisms: +- Organism/Card/Feature/Default +- Organism/Navigation/Desktop/Default +- Organism/Navigation/Mobile/Collapsed +- Organism/Footer/TwoColumn/Default +``` + +### 7.3 Component States & Variants + +**Every interactive component should have states:** + +``` +Button/Primary/ +├── Default # Resting state +├── Hover # Mouse over +├── Active # Pressed/clicked +├── Focus # Keyboard focus +├── Disabled # Non-interactive +└── Loading # Processing state (with spinner) +``` + +**Implementation in Pencil:** +```json +{ + "type": "frame", + "id": "BtnPrimary_Default", + "name": "Atom/Button/Primary/Default", + "reusable": true, + "fill": { + "type": "gradient", + "colors": [ + {"color": "#FF5C00", "position": 0}, + {"color": "#FF8A4C", "position": 1} + ] + } +} + +// Hover state - slightly brighter +{ + "type": "frame", + "id": "BtnPrimary_Hover", + "name": "Atom/Button/Primary/Hover", + "reusable": true, + "fill": { + "type": "gradient", + "colors": [ + {"color": "#FF6E1A", "position": 0}, + {"color": "#FF9C66", "position": 1} + ] + } +} + +// Disabled state - reduced opacity +{ + "type": "frame", + "id": "BtnPrimary_Disabled", + "name": "Atom/Button/Primary/Disabled", + "reusable": true, + "fill": "#6B6B70", + "opacity": 0.5 +} +``` + +### 7.4 Responsive Component Variants + +**Desktop/Tablet/Mobile patterns:** + +``` +Organism/Navigation/ +├── Desktop/ +│ ├── Default # Full horizontal nav with all items +│ └── Scrolled # Sticky/collapsed on scroll +├── Tablet/ +│ ├── Default # Hybrid with some collapsed items +│ └── MenuOpen # Sidebar drawer +└── Mobile/ + ├── Collapsed # Hamburger icon only + └── Expanded # Full-screen menu overlay +``` + +**Breakpoint tokens in design-tokens.pen:** +```json +"variables": { + "breakpoint-mobile": {"type": "number", "value": 390}, + "breakpoint-tablet": {"type": "number", "value": 768}, + "breakpoint-desktop": {"type": "number", "value": 1440} +} +``` + +### 7.3 Project Structure with Build System + +**Recommended structure:** +``` +project-name/ +├── src/ +│ ├── components/ +│ │ └── ui-kit.pen # Component library + design tokens +│ └── pages/ +│ ├── desktop-home.pen # Desktop (1440px) +│ ├── mobile-home.pen # Mobile (390px) +│ └── tablet-home.pen # Tablet (768px) +├── build/ # Standard build output (gitignore) +│ ├── desktop-home.pen # With injected components +│ └── ... +├── scripts/ +│ └── build.py # Build script +├── pencil.config.json # Build configuration +├── tPOS.pen # Monolithic build output +└── USAGE_GUIDE.md # Documentation +``` + +### 7.4 Modular Design Architecture (Hybrid Approach) **Problem**: Large monolithic `.pen` files (5000+ lines) cause: - ❌ Slow performance (2-3 second load times) @@ -253,7 +513,7 @@ project-name/ │ └── footer.pen ``` -**Option C: Hybrid** ⭐ (Recommended) +**Option C: Hybrid** ⭐ (Recommended for Medium Projects) ``` project-name/ ├── components/ @@ -265,6 +525,65 @@ project-name/ └── USAGE_GUIDE.md # Workflow docs ``` +**Option D: Atomic Design Hierarchy** 🏆 (Recommended for Enterprise) +``` +project-name/ +├── src/ +│ ├── foundations/ +│ │ └── design-tokens.pen # Design system variables +│ │ +│ ├── atoms/ # Smallest building blocks +│ │ ├── buttons.pen # All button variants & states +│ │ ├── inputs.pen # Text fields, checkboxes, radio +│ │ ├── badges.pen # Badges, chips, pills, tags +│ │ ├── icons.pen # Icon library (if custom) +│ │ └── typography.pen # Headings, body text, labels +│ │ +│ ├── molecules/ # Combinations of atoms +│ │ ├── form-fields.pen # Label + Input + Error +│ │ ├── search-bar.pen # Input + Icon + Button +│ │ ├── card-headers.pen # Icon + Title + Badge +│ │ └── navigation-items.pen # Icon + Text + Badge +│ │ +│ ├── organisms/ # Complex UI sections +│ │ ├── cards.pen # Feature, pricing, step cards +│ │ ├── navigation.pen # Top nav, sidebar, mobile menu +│ │ ├── headers.pen # Page & section headers +│ │ ├── footers.pen # Footer variants +│ │ └── forms.pen # Complete form layouts +│ │ +│ ├── templates/ # Page layouts (optional) +│ │ ├── dashboard-layout.pen +│ │ ├── landing-layout.pen +│ │ └── auth-layout.pen +│ │ +│ └── pages/ # Complete pages +│ ├── desktop-home.pen +│ ├── mobile-home.pen +│ └── tablet-home.pen +│ +├── build/ # Build output (gitignore) +├── scripts/ +│ └── build.py # Build script +├── pencil.config.json +└── USAGE_GUIDE.md +``` + +**Benefits of Atomic Design:** +- ✅ **Industry Standard** - Used by Figma, Material Design, Ant Design +- ✅ **Maximum Scalability** - Easy to add components at any level +- ✅ **Clear Hierarchy** - Atoms → Molecules → Organisms → Templates → Pages +- ✅ **Team Collaboration** - Different designers own different atomic levels +- ✅ **Reusability** - Components compose naturally from smaller pieces +- ✅ **Discoverability** - Intuitive folder structure for finding components + +**When to use Atomic Design:** +- ✅ Enterprise applications with 50+ components +- ✅ Design system shared across multiple products +- ✅ Team of 3+ designers working in parallel +- ✅ Long-term maintenance (2+ years) +- ✅ Need component documentation & showcases + #### Component Library Structure **ui-kit.pen should contain:** @@ -419,9 +738,272 @@ Components are COPIED, not linked - Prototypes or wireframes - File < 2,000 lines -## 7. Best Practices +#### Atomic Design Extraction Workflow -### 7.1 Khi đọc .pen files +**For large enterprise UI Kits (2,000+ lines), convert to Atomic Design structure:** + +**Step 1: Audit Components** +```bash +# Analyze current structure +grep '"name":' tPOS-ui-kit.pen | grep -i "button" > buttons-list.txt +grep '"name":' tPOS-ui-kit.pen | grep -i "badge" > badges-list.txt +grep '"name":' tPOS-ui-kit.pen | grep -i "card" > cards-list.txt + +# Count components by category +echo "Buttons: $(grep -c button buttons-list.txt)" +echo "Badges: $(grep -c badge badges-list.txt)" +echo "Cards: $(grep -c card cards-list.txt)" +``` + +**Step 2: Create Atomic Structure** +```bash +mkdir -p src/foundations src/atoms src/molecules src/organisms src/pages +``` + +**Step 3: Extract to Atomic Files** +```python +import json +import os + +# Read monolithic UI Kit +with open('tPOS-ui-kit.pen', 'r') as f: + data = json.load(f) + +variables = data['variables'] +main_page = data['children'][0] # Component Library page +sections = main_page['children'] # All sections + +# 1. Extract design tokens +tokens_file = { + 'version': '2.6', + 'children': [{ + 'type': 'frame', + 'name': 'Design Tokens Reference', + 'layout': 'vertical', + 'gap': 20, + 'children': [ + { + 'type': 'text', + 'name': 'Title', + 'content': 'Design System Tokens', + 'fontSize': 32, + 'fill': '$text-primary' + } + ] + }], + 'variables': variables +} + +with open('src/foundations/design-tokens.pen', 'w') as f: + json.dump(tokens_file, f, indent=2) + +# 2. Categorize components by atomic level +atomic_mapping = { + 'atoms': { + 'patterns': ['button', 'badge', 'input', 'icon', 'typography', 'chip'], + 'components': [] + }, + 'molecules': { + 'patterns': ['formfield', 'searchbar', 'cardheader'], + 'components': [] + }, + 'organisms': { + 'patterns': ['card', 'navigation', 'header', 'footer', 'form'], + 'components': [] + } +} + +# Categorize each section +for section in sections: + section_name = section.get('name', '').lower() + + # Determine atomic level + matched = False + for level, config in atomic_mapping.items(): + for pattern in config['patterns']: + if pattern in section_name: + config['components'].append(section) + matched = True + break + if matched: + break + +# 3. Generate atomic files +for level, config in atomic_mapping.items(): + if not config['components']: + continue + + # Group by component type + grouped = {} + for component in config['components']: + name = component.get('name', '') + # Extract type (e.g., "Buttons & Actions Section" -> "buttons") + comp_type = name.lower().split()[0].replace('&', '').strip() + + if comp_type not in grouped: + grouped[comp_type] = [] + grouped[comp_type].append(component) + + # Create file for each type + for comp_type, components in grouped.items(): + output_file = { + 'version': '2.6', + 'children': components, + 'variables': variables + } + + filepath = f'src/{level}/{comp_type}.pen' + with open(filepath, 'w') as f: + json.dump(output_file, f, indent=2) + + print(f'✅ Created {filepath} with {len(components)} sections') + +print(f'\n🎉 Atomic Design structure created!') +print(f'📁 Foundations: src/foundations/design-tokens.pen') +print(f'⚛️ Atoms: {len(atomic_mapping["atoms"]["components"])} files') +print(f'🧬 Molecules: {len(atomic_mapping["molecules"]["components"])} files') +print(f'🦠 Organisms: {len(atomic_mapping["organisms"]["components"])} files') +``` + +**Step 4: Create Showcase Files** + +Each atomic file should have a showcase page: + +```python +# Add showcase page to each atomic file +import json +import os +from pathlib import Path + +for atomic_dir in ['src/atoms', 'src/molecules', 'src/organisms']: + for filepath in Path(atomic_dir).glob('*.pen'): + with open(filepath, 'r') as f: + data = json.load(f) + + # Wrap components in a showcase page + showcase = { + 'type': 'frame', + 'name': f'{filepath.stem.title()} Showcase', + 'width': 1440, + 'fill': '$bg-page', + 'layout': 'vertical', + 'gap': 80, + 'padding': [80, 120], + 'children': data['children'] + } + + data['children'] = [showcase] + + with open(filepath, 'w') as f: + json.dump(data, f, indent=2) + + print(f'✅ Added showcase to {filepath}') +``` + +**Step 5: Validate Structure** +```python +import json +import os +from pathlib import Path + +required_structure = [ + 'src/foundations/design-tokens.pen', + 'src/atoms', + 'src/molecules', + 'src/organisms' +] + +for path in required_structure: + if not os.path.exists(path): + print(f'❌ Missing: {path}') + else: + if path.endswith('.pen'): + with open(path, 'r') as f: + data = json.load(f) + assert 'version' in data + assert 'variables' in data + print(f'✅ Valid: {path}') + else: + files = list(Path(path).glob('*.pen')) + print(f'✅ {path}: {len(files)} files') + +print('\n🎉 Atomic Design structure validated!') +``` + +**Step 6: Create Usage Guide** + +Generate `USAGE_GUIDE.md`: + +```markdown +# tPOS Design System - Atomic Design Structure + +## Structure Overview + +\`\`\` +src/ +├── foundations/ +│ └── design-tokens.pen # Colors, typography, spacing, breakpoints +├── atoms/ # Smallest building blocks +├── molecules/ # Simple combinations +├── organisms/ # Complex components +└── pages/ # Complete pages +\`\`\` + +## Atomic Levels + +### Foundations +- **File**: `design-tokens.pen` +- **Contains**: CSS variables, color palette, typography scale, spacing system +- **Usage**: Copy variables to all component files + +### Atoms +- **Examples**: Buttons, inputs, badges, icons, typography +- **Characteristics**: Cannot be broken down further +- **States**: Default, Hover, Active, Disabled + +### Molecules +- **Examples**: Form fields, search bars, card headers +- **Characteristics**: Combinations of 2-3 atoms +- **Usage**: Import atoms and compose + +### Organisms +- **Examples**: Cards, navigation, headers, footers +- **Characteristics**: Complex sections with multiple molecules +- **Usage**: Complete, reusable UI sections + +## Workflow + +1. **Update Foundation**: Edit `design-tokens.pen` for colors/typography changes +2. **Sync Tokens**: Copy `variables` object to all modified component files +3. **Build Components**: Edit atomic files with proper naming (Atom/Button/Primary/Default) +4. **Compose Up**: Molecules use atoms, organisms use molecules +5. **Test in Pages**: Reference components in page files +6. **Build**: Run `python3 scripts/build.py -m` for monolithic output + +## Component Naming + +\`\`\` +{Level}/{Component}/{Variant}/{State} + +Examples: +- Atom/Button/Primary/Default +- Molecule/FormField/Text/WithError +- Organism/Card/Feature/Default +\`\`\` + +## Best Practices + +1. ✅ **Design Tokens First**: Always update foundation before components +2. ✅ **Build Up**: Atoms → Molecules → Organisms → Pages +3. ✅ **Consistent States**: All interactive components need states +4. ✅ **Reusable**: Set `"reusable": true` on all shareable components +5. ✅ **Version Control**: Commit src/ files, gitignore build/ +\`\`\` +``` + +## 8. Best Practices + +### 8.1 Khi đọc .pen files 1. **Luôn kiểm tra `version`** - Đảm bảo compatibility 2. **Tìm page chính** - Thường là frame có name kết thúc bằng "Page" @@ -429,14 +1011,23 @@ Components are COPIED, not linked 4. **Map components** - List ra reusable components trước 5. **Check file size** - Nếu > 300KB, consider splitting -### 7.2 Khi convert sang code +### 8.2 Khi convert sang code 1. **Mobile-first** - Responsive breakpoints 2. **Semantic HTML** - `
`, `
`, `
`, `