design system patterns
14
总安装量
0
周安装量
#23668
全站排名
安装命令
npx skills add https://github.com/gyejoon/pencil-plugin --skill Design System Patterns
Skill 文档
Design System Patterns
Pencilìì ëìì¸ ìì¤í ì 구ì¶íê³ ê´ë¦¬íë í¨í´ê³¼ ëª¨ë² ì¬ë¡ë¥¼ ì ê³µíë¤.
Core Concepts
ëìì¸ í í°
ëìì¸ í í°ì ëìì¸ ìì¤í ì 기본 ë¨ìë¡, ë³ìë¡ ì ìíì¬ ì¼ê´ì±ì ì ì§íë¤.
| Token Type | ìì | ì©ë |
|---|---|---|
| Colors | primary, secondary, neutral | ë¸ëë ìì, UI ìì |
| Typography | heading, body, caption | í°í¸ í¬ê¸°, 굵기, íê° |
| Spacing | xs, sm, md, lg, xl | ì¬ë°±, ê°ê²© |
| Radii | sm, md, lg, full | 모ì리 ë¥ê¸ê¸° |
| Shadows | sm, md, lg | 그림ì í¨ê³¼ |
ì»´í¬ëí¸ ê³ì¸µ
Primitives (기본 ìì)
âââ Atoms (ìì: Button, Input, Badge)
âââ Molecules (ë¶ì: SearchBar, Card, MenuItem)
âââ Organisms (ì 기체: Header, Sidebar, Form)
âââ Templates (í
í릿: PageLayout, DashboardLayout)
Variables Management
get_variablesë¡ ì¡°í
mcp__pencil__get_variables(filePath: string)
íì¬ ì ìë 모ë ë³ìì í ë§ë¥¼ ë°ííë¤.
set_variablesë¡ ì¤ì
mcp__pencil__set_variables(
filePath: string,
variables: object,
replace?: boolean
)
ë³ì 구조 ìì
{
"colors": {
"primary": {
"50": "#EFF6FF",
"100": "#DBEAFE",
"500": "#3B82F6",
"600": "#2563EB",
"700": "#1D4ED8"
},
"neutral": {
"50": "#F8FAFC",
"100": "#F1F5F9",
"500": "#64748B",
"900": "#0F172A"
}
},
"typography": {
"fontFamily": "Inter, sans-serif",
"fontSize": {
"xs": 12,
"sm": 14,
"base": 16,
"lg": 18,
"xl": 20,
"2xl": 24,
"3xl": 30
},
"fontWeight": {
"normal": 400,
"medium": 500,
"semibold": 600,
"bold": 700
}
},
"spacing": {
"0": 0,
"1": 4,
"2": 8,
"3": 12,
"4": 16,
"5": 20,
"6": 24,
"8": 32,
"10": 40,
"12": 48
},
"radii": {
"none": 0,
"sm": 4,
"md": 8,
"lg": 12,
"xl": 16,
"full": 9999
}
}
ë³ì 참조
ë ¸ë ìì±ìì ë³ì 참조:
button=I("parentId", {
type: "frame",
fill: "var(colors/primary/500)",
padding: "var(spacing/4)",
cornerRadius: "var(radii/md)"
})
label=I(button, {
type: "text",
content: "Button",
fontSize: "var(typography/fontSize/base)",
fontWeight: "var(typography/fontWeight/medium)",
textColor: "#FFFFFF"
})
Creating Reusable Components
ì»´í¬ëí¸ ì ì
reusable: true ìì±ì¼ë¡ ì»´í¬ëí¸ ë±ë¡:
// Button ì»´í¬ëí¸ ì ì
buttonComp=I(document, {
type: "frame",
name: "Button",
reusable: true,
layout: "horizontal",
padding: [12, 24, 12, 24],
alignItems: "center",
justifyContent: "center",
gap: 8,
fill: "var(colors/primary/500)",
cornerRadius: "var(radii/md)"
})
btnLabel=I(buttonComp, {
type: "text",
name: "label",
content: "Button",
textColor: "#FFFFFF",
fontWeight: "var(typography/fontWeight/medium)"
})
ì»´í¬ëí¸ ì¸ì¤í´ì¤ ì¬ì©
// ì»´í¬ëí¸ ì¸ì¤í´ì¤ ìì±
btn1=I("formId", { type: "ref", ref: "buttonCompId" })
// ì¸ì¤í´ì¤ ë´ë¶ ìì
U(btn1+"/label", { content: "Submit" })
ì»´í¬ëí¸ Variants
ìíë³ ë³íì ë³ë ì»´í¬ëí¸ë¡ ì ì:
// Primary Button
primaryBtn=I(document, {
type: "frame",
name: "Button/Primary",
reusable: true,
fill: "var(colors/primary/500)"
// ... rest
})
// Secondary Button
secondaryBtn=I(document, {
type: "frame",
name: "Button/Secondary",
reusable: true,
fill: "transparent",
stroke: "var(colors/primary/500)",
strokeWidth: 1
// ... rest
})
// Ghost Button
ghostBtn=I(document, {
type: "frame",
name: "Button/Ghost",
reusable: true,
fill: "transparent"
// ... rest
})
Common Component Patterns
Button
button=I(document, {
type: "frame",
name: "Button",
reusable: true,
layout: "horizontal",
padding: [12, 24, 12, 24],
alignItems: "center",
justifyContent: "center",
gap: 8,
fill: "var(colors/primary/500)",
cornerRadius: "var(radii/md)"
})
icon=I(button, {
type: "frame",
name: "iconSlot",
width: 20,
height: 20,
placeholder: true
})
label=I(button, {
type: "text",
name: "label",
content: "Button",
fontSize: "var(typography/fontSize/base)",
fontWeight: "var(typography/fontWeight/medium)",
textColor: "#FFFFFF"
})
Input Field
inputField=I(document, {
type: "frame",
name: "InputField",
reusable: true,
layout: "vertical",
gap: 8,
width: "fill_container"
})
label=I(inputField, {
type: "text",
name: "label",
content: "Label",
fontSize: "var(typography/fontSize/sm)",
fontWeight: "var(typography/fontWeight/medium)"
})
input=I(inputField, {
type: "frame",
name: "input",
layout: "horizontal",
width: "fill_container",
height: 44,
padding: [0, 16, 0, 16],
alignItems: "center",
fill: "#FFFFFF",
stroke: "var(colors/neutral/200)",
strokeWidth: 1,
cornerRadius: "var(radii/md)"
})
placeholder=I(input, {
type: "text",
name: "placeholder",
content: "Enter value...",
textColor: "var(colors/neutral/400)"
})
helper=I(inputField, {
type: "text",
name: "helperText",
content: "",
fontSize: "var(typography/fontSize/xs)",
textColor: "var(colors/neutral/500)"
})
Card
card=I(document, {
type: "frame",
name: "Card",
reusable: true,
layout: "vertical",
width: 320,
fill: "#FFFFFF",
cornerRadius: "var(radii/lg)",
clipContent: true
})
media=I(card, {
type: "frame",
name: "mediaSlot",
width: "fill_container",
height: 180,
placeholder: true
})
content=I(card, {
type: "frame",
name: "content",
layout: "vertical",
padding: 24,
gap: 12
})
title=I(content, {
type: "text",
name: "title",
content: "Card Title",
fontSize: "var(typography/fontSize/lg)",
fontWeight: "var(typography/fontWeight/semibold)"
})
description=I(content, {
type: "text",
name: "description",
content: "Card description...",
textColor: "var(colors/neutral/600)"
})
actions=I(card, {
type: "frame",
name: "actionsSlot",
layout: "horizontal",
padding: [0, 24, 24, 24],
gap: 12,
placeholder: true
})
Theming
í ë§ ì¶ ì ì
ë¼ì´í¸/ë¤í¬ 모ë ì§ì:
{
"themeAxes": {
"mode": ["light", "dark"]
},
"colors": {
"background": {
"mode:light": "#FFFFFF",
"mode:dark": "#0F172A"
},
"text": {
"primary": {
"mode:light": "#0F172A",
"mode:dark": "#F8FAFC"
},
"secondary": {
"mode:light": "#64748B",
"mode:dark": "#94A3B8"
}
}
}
}
í ë§ ì ì©
// ë³ì 참조 ì íì¬ í
ë§ ê° ìë ì ì©
container=I("parentId", {
type: "frame",
fill: "var(colors/background)"
})
title=I(container, {
type: "text",
content: "Title",
textColor: "var(colors/text/primary)"
})
Best Practices
Naming Conventions
- ì»´í¬ëí¸: PascalCase (
Button,InputField,Card) - Variants: Slash êµ¬ë¶ (
Button/Primary,Button/Secondary) - ë´ë¶ ë
¸ë: camelCase (
label,iconSlot,contentArea) - ë³ì: lowercase/ì¬ëì (
colors/primary/500,spacing/4)
Component Organization
- Primitives first: 기본 ììë¶í° ì ì
- Compose up: ìì ì»´í¬ëí¸ë¡ í° ì»´í¬ëí¸ êµ¬ì±
- Single responsibility: íëì ìí ë§ ë´ë¹
- Prop slots: placeholderë¡ ì»¤ì¤í°ë§ì´ì§ ì§ì ì ê³µ
Variable Usage
- Consistent tokens: íëì½ë© ëì ë³ì 참조
- Semantic names: ì©ë ê¸°ë° ì´ë¦ (primary, danger, not blue, red)
- Scale systems: ì¼ê´ë ì¤ì¼ì¼ (4px ë¨ì ì¤íì´ì±)
Additional Resources
Reference Files
references/token-scales.md– íì¤ í í° ì¤ì¼ì¼ ì ìreferences/component-catalog.md– ê³µíµ ì»´í¬ëí¸ ì¹´íë¡ê·¸