feat: Refactor mode switch component and enhance design tokens for improved UI consistency and functionality.
This commit is contained in:
@@ -275,86 +275,23 @@ python3 scripts/build.py --library
|
||||
|
||||
## Common Mistakes / Lỗi Thường Gặp
|
||||
|
||||
### 1. Hardcoding Colors
|
||||
**Problem**: Using hex codes directly in components (e.g. `#000000`), making theming impossible.
|
||||
**Solution**: Always use design token variables.
|
||||
> [!TIP]
|
||||
> See [Pitfalls Reference](./references/PITFALLS.md) for detailed examples and solutions.
|
||||
|
||||
```css
|
||||
/* ❌ BAD: Hardcoded colors */
|
||||
background: #0A0A0B;
|
||||
| # | Pitfall | Quick Fix |
|
||||
|---|---------|-----------|
|
||||
| 1 | Hardcoding colors | Use `$token` variables |
|
||||
| 2 | Ignoring `ref` system | Resolve refs by component ID |
|
||||
| 3 | Opening source files directly | Build first: `python3 scripts/build.py -m` |
|
||||
| 4 | Direct hex values | Use `$orange-primary` not `#FF5C00` |
|
||||
| 5 | Centering without width | Add `width: "fill_container"` |
|
||||
| 6 | Font weight as number | Use `type: "string"`, `value: "500"` |
|
||||
| 7 | Empty `variables: {}` | Define all used tokens |
|
||||
| 8 | Token refs in fontSize | Use numbers directly: `fontSize: 14` |
|
||||
| 9 | Emoji text for icons | Use `icon_font` with Lucide |
|
||||
| 10 | `glob()` missing subdirs | Use `rglob()` for recursive scan |
|
||||
| 11 | Components at root level | Wrap in Showcase frame with layout |
|
||||
|
||||
/* ✅ GOOD: Use CSS variables */
|
||||
background: var(--bg-page);
|
||||
```
|
||||
|
||||
### 2. Ignoring Referencing System
|
||||
**Problem**: Treating `ref` elements as normal frames, losing link to main component.
|
||||
**Solution**: Resolve `ref` by looking up the component ID.
|
||||
|
||||
```javascript
|
||||
// ❌ BAD: Skip ref elements
|
||||
if (element.type === 'ref') return;
|
||||
|
||||
// ✅ GOOD: Resolve ref properly
|
||||
if (element.type === 'ref') {
|
||||
const component = findById(element.ref);
|
||||
return mergeWithDescendants(component, element.descendants);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Modifying Source Files Directly
|
||||
**Problem**: Open and editing partial files in `src/` without building, causing "Missing Component" errors in Pencil.
|
||||
**Solution**: Always run build script before opening in Pencil.
|
||||
|
||||
```bash
|
||||
# ❌ BAD: Open source files directly
|
||||
open src/pages/desktop-home.pen
|
||||
|
||||
# ✅ GOOD: Build first
|
||||
python3 scripts/build.py -m
|
||||
open tPOS.pen
|
||||
```
|
||||
|
||||
### 4. Direct Value Usage
|
||||
**Problem**: Using numeric values for spacing/fontsize, breaking design system consistency.
|
||||
**Solution**: Use semantic variables.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Direct values
|
||||
{
|
||||
"fill": "#FF5C00",
|
||||
"fontSize": 16
|
||||
}
|
||||
|
||||
// ✅ GOOD: Use variables
|
||||
{
|
||||
"fill": "$orange-primary",
|
||||
"fontSize": "$text-lg"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Missing Width for Centering
|
||||
**Problem**: Setting `alignItems: "center"` without explicit width. The frame only takes content width, making horizontal centering ineffective.
|
||||
**Solution**: Add `width: "fill_container"` to parent frame.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Centering won't work
|
||||
{
|
||||
"type": "frame",
|
||||
"layout": "vertical",
|
||||
"alignItems": "center",
|
||||
"children": [...]
|
||||
}
|
||||
|
||||
// ✅ GOOD: Explicit width enables centering
|
||||
{
|
||||
"type": "frame",
|
||||
"width": "fill_container",
|
||||
"layout": "vertical",
|
||||
"alignItems": "center",
|
||||
"children": [...]
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Reference / Tham Chiếu Nhanh
|
||||
|
||||
|
||||
315
.agent/skills/pencil-design/references/PITFALLS.md
Normal file
315
.agent/skills/pencil-design/references/PITFALLS.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# Pencil Design Pitfalls / Lỗi Thường Gặp
|
||||
|
||||
Comprehensive list of common mistakes when working with Pencil `.pen` files and their solutions.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Hardcoding Colors](#1-hardcoding-colors)
|
||||
2. [Ignoring Referencing System](#2-ignoring-referencing-system)
|
||||
3. [Modifying Source Files Directly](#3-modifying-source-files-directly)
|
||||
4. [Direct Value Usage](#4-direct-value-usage)
|
||||
5. [Missing Width for Centering](#5-missing-width-for-centering)
|
||||
6. [Font Weight Variables Type Error](#6-font-weight-variables-type-error)
|
||||
7. [Empty Variables Block](#7-empty-variables-block)
|
||||
8. [Token References in Numeric Fields](#8-token-references-in-numeric-fields)
|
||||
9. [Using Emoji Text for Icons](#9-using-emoji-text-for-icons)
|
||||
10. [Build Script Not Scanning Subdirectories](#10-build-script-not-scanning-subdirectories)
|
||||
11. [Components at Root Level](#11-components-at-root-level)
|
||||
|
||||
---
|
||||
|
||||
## 1. Hardcoding Colors
|
||||
|
||||
**Problem**: Using hex codes directly in components (e.g. `#000000`), making theming impossible.
|
||||
|
||||
**Solution**: Always use design token variables.
|
||||
|
||||
```css
|
||||
/* ❌ BAD: Hardcoded colors */
|
||||
background: #0A0A0B;
|
||||
|
||||
/* ✅ GOOD: Use CSS variables */
|
||||
background: var(--bg-page);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Ignoring Referencing System
|
||||
|
||||
**Problem**: Treating `ref` elements as normal frames, losing link to main component.
|
||||
|
||||
**Solution**: Resolve `ref` by looking up the component ID.
|
||||
|
||||
```javascript
|
||||
// ❌ BAD: Skip ref elements
|
||||
if (element.type === 'ref') return;
|
||||
|
||||
// ✅ GOOD: Resolve ref properly
|
||||
if (element.type === 'ref') {
|
||||
const component = findById(element.ref);
|
||||
return mergeWithDescendants(component, element.descendants);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Modifying Source Files Directly
|
||||
|
||||
**Problem**: Opening and editing partial files in `src/` without building, causing "Missing Component" errors in Pencil.
|
||||
|
||||
**Solution**: Always run build script before opening in Pencil.
|
||||
|
||||
```bash
|
||||
# ❌ BAD: Open source files directly
|
||||
open src/pages/desktop-home.pen
|
||||
|
||||
# ✅ GOOD: Build first
|
||||
python3 scripts/build.py -m
|
||||
open tPOS.pen
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Direct Value Usage
|
||||
|
||||
**Problem**: Using numeric values for spacing/fontsize, breaking design system consistency.
|
||||
|
||||
**Solution**: Use semantic variables (for colors only - see #8).
|
||||
|
||||
```json
|
||||
// ❌ BAD: Direct color values
|
||||
{
|
||||
"fill": "#FF5C00"
|
||||
}
|
||||
|
||||
// ✅ GOOD: Use color variables
|
||||
{
|
||||
"fill": "$orange-primary"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Missing Width for Centering
|
||||
|
||||
**Problem**: Setting `alignItems: "center"` without explicit width. The frame only takes content width, making horizontal centering ineffective.
|
||||
|
||||
**Solution**: Add `width: "fill_container"` to parent frame.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Centering won't work
|
||||
{
|
||||
"type": "frame",
|
||||
"layout": "vertical",
|
||||
"alignItems": "center",
|
||||
"children": [...]
|
||||
}
|
||||
|
||||
// ✅ GOOD: Explicit width enables centering
|
||||
{
|
||||
"type": "frame",
|
||||
"width": "fill_container",
|
||||
"layout": "vertical",
|
||||
"alignItems": "center",
|
||||
"children": [...]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Font Weight Variables Type Error
|
||||
|
||||
**Problem**: Defining font-weight variables with `type: "number"` causes Pencil to fail with:
|
||||
```
|
||||
Variable 'font-medium' has type 'number' (expected 'string')
|
||||
```
|
||||
|
||||
**Solution**: Font weights MUST use `type: "string"` with quoted values.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Number type
|
||||
"font-medium": { "type": "number", "value": 500 }
|
||||
|
||||
// ✅ GOOD: String type with quoted value
|
||||
"font-medium": { "type": "string", "value": "500" }
|
||||
```
|
||||
|
||||
**All font weight variables to fix:**
|
||||
```json
|
||||
"font-normal": { "type": "string", "value": "400" },
|
||||
"font-medium": { "type": "string", "value": "500" },
|
||||
"font-semibold": { "type": "string", "value": "600" },
|
||||
"font-bold": { "type": "string", "value": "700" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Empty Variables Block
|
||||
|
||||
**Problem**: Using token references like `$orange-primary` but leaving `variables: {}` empty. Tokens won't resolve and colors appear wrong.
|
||||
|
||||
**Solution**: Always define all used tokens in the file's `variables` block.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Empty variables but using $tokens
|
||||
{
|
||||
"children": [{ "fill": "$orange-primary" }],
|
||||
"variables": {}
|
||||
}
|
||||
|
||||
// ✅ GOOD: Define all used tokens
|
||||
{
|
||||
"children": [{ "fill": "$orange-primary" }],
|
||||
"variables": {
|
||||
"orange-primary": { "type": "color", "value": "#FF5C00" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Token References in Numeric Fields
|
||||
|
||||
**Problem**: Using token syntax (`$text-sm`) for properties that MUST be numbers: `fontSize`, `fontWeight`, `cornerRadius`, `width`, `height`.
|
||||
|
||||
**Solution**: Use actual numbers for numeric properties. Only colors support token refs.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Token in fontSize (won't work)
|
||||
{
|
||||
"fontSize": "$text-sm",
|
||||
"fontWeight": "$font-medium",
|
||||
"cornerRadius": "$radius-md"
|
||||
}
|
||||
|
||||
// ✅ GOOD: Direct numeric values
|
||||
{
|
||||
"fontSize": 14,
|
||||
"fontWeight": "500",
|
||||
"cornerRadius": 8
|
||||
}
|
||||
|
||||
// ✅ ALSO OK: Tokens for colors only
|
||||
{ "fill": "$text-primary" }
|
||||
```
|
||||
|
||||
**Rule of thumb:**
|
||||
- Color properties (`fill`, `stroke`) → Use `$tokens`
|
||||
- Numeric properties → Use numbers directly
|
||||
|
||||
---
|
||||
|
||||
## 9. Using Emoji Text for Icons
|
||||
|
||||
**Problem**: Emoji characters in `type: "text"` don't render in Pencil.
|
||||
|
||||
**Solution**: Use `type: "icon_font"` with Lucide icons.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Emoji text (won't render)
|
||||
{ "type": "text", "content": "🍽️", "fontSize": 16 }
|
||||
|
||||
// ✅ GOOD: Lucide icon_font
|
||||
{
|
||||
"type": "icon_font",
|
||||
"id": "RestaurantIcon",
|
||||
"iconFontName": "utensils",
|
||||
"iconFontFamily": "lucide",
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"fill": "#FFFFFF"
|
||||
}
|
||||
```
|
||||
|
||||
**Common Lucide icon mappings:**
|
||||
|
||||
| Emoji | Lucide Name | Use Case |
|
||||
|-------|-------------|----------|
|
||||
| 🍽️ | `utensils` | Restaurant |
|
||||
| 🍸 | `wine` | Bar |
|
||||
| 🎤 | `mic` | Karaoke |
|
||||
| 💆 | `sparkles` | Spa |
|
||||
| ✓ | `check` | Success |
|
||||
| ✗ | `x` | Close/Error |
|
||||
| + | `plus` | Add |
|
||||
| - | `minus` | Remove |
|
||||
| 🔍 | `search` | Search |
|
||||
| ⚙️ | `settings` | Settings |
|
||||
| 👤 | `user` | Profile |
|
||||
| 🏠 | `home` | Home |
|
||||
| 💳 | `credit-card` | Payment |
|
||||
| 🛒 | `shopping-cart` | Cart |
|
||||
|
||||
---
|
||||
|
||||
## 10. Build Script Not Scanning Subdirectories
|
||||
|
||||
**Problem**: Using `glob('*.pen')` only scans top-level files, missing subdirectories like `organisms/vertical-specific/`.
|
||||
|
||||
**Solution**: Use `rglob('*.pen')` to scan recursively.
|
||||
|
||||
```python
|
||||
# ❌ BAD: Only top-level files
|
||||
for pen_file in dir_path.glob('*.pen'):
|
||||
|
||||
# ✅ GOOD: Include subdirectories
|
||||
for pen_file in dir_path.rglob('*.pen'):
|
||||
```
|
||||
|
||||
**In `scripts/build.py`:**
|
||||
```python
|
||||
# Line ~367
|
||||
for pen_file in sorted(dir_path.rglob('*.pen')):
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Components at Root Level
|
||||
|
||||
**Problem**: Placing multiple reusable components at root `children[]` causes them to stack/overlap incorrectly in Pencil.
|
||||
|
||||
**Solution**: Wrap in a Showcase frame with layout.
|
||||
|
||||
```json
|
||||
// ❌ BAD: Components at root level (will overlap)
|
||||
{
|
||||
"children": [
|
||||
{ "name": "Component/A", "reusable": true },
|
||||
{ "name": "Component/B", "reusable": true }
|
||||
]
|
||||
}
|
||||
|
||||
// ✅ GOOD: Wrapped in Showcase frame
|
||||
{
|
||||
"children": [
|
||||
{
|
||||
"type": "frame",
|
||||
"name": "Component Showcase",
|
||||
"width": 1200,
|
||||
"fill": "$bg-page",
|
||||
"layout": "vertical",
|
||||
"gap": 40,
|
||||
"padding": 40,
|
||||
"children": [
|
||||
{ "name": "Component/A", "reusable": true },
|
||||
{ "name": "Component/B", "reusable": true }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Checklist / Checklist Nhanh
|
||||
|
||||
Before committing `.pen` files:
|
||||
|
||||
- [ ] All `font-*` variables use `type: "string"`
|
||||
- [ ] `variables` block contains all used tokens
|
||||
- [ ] No `$tokens` in numeric fields (fontSize, cornerRadius, etc.)
|
||||
- [ ] Icons use `icon_font` not emoji text
|
||||
- [ ] Build script uses `rglob()` for subdirectories
|
||||
- [ ] Components wrapped in layout frames, not at root level
|
||||
- [ ] Run `jq empty file.pen` to validate JSON syntax
|
||||
- [ ] Run `python3 scripts/build.py --library` before testing
|
||||
Reference in New Issue
Block a user