stitch-kit 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +139 -0
- package/CHANGELOG.md +86 -0
- package/README.md +167 -0
- package/agents/stitch-kit.md +93 -0
- package/bin/stitch-kit.mjs +430 -0
- package/docs/architecture.md +118 -0
- package/docs/color-prompt-guide.md +119 -0
- package/docs/mcp-naming-convention.md +64 -0
- package/docs/mcp-schemas/README.md +130 -0
- package/docs/mcp-schemas/apply_design_system.json +36 -0
- package/docs/mcp-schemas/create_design_system.json +78 -0
- package/docs/mcp-schemas/create_project.json +290 -0
- package/docs/mcp-schemas/delete_project.json +20 -0
- package/docs/mcp-schemas/edit_screens.json +46 -0
- package/docs/mcp-schemas/generate_screen_from_text.json +242 -0
- package/docs/mcp-schemas/generate_variants.json +77 -0
- package/docs/mcp-schemas/get_project.json +137 -0
- package/docs/mcp-schemas/get_screen.json +92 -0
- package/docs/mcp-schemas/list_design_systems.json +32 -0
- package/docs/mcp-schemas/list_projects.json +136 -0
- package/docs/mcp-schemas/list_screens.json +56 -0
- package/docs/mcp-schemas/update_design_system.json +32 -0
- package/docs/mcp-schemas/upload_screens_from_images.json +52 -0
- package/docs/prd-to-stitch-workflow.md +137 -0
- package/docs/skills-index.md +108 -0
- package/docs/tailwind-reference.md +207 -0
- package/package.json +41 -0
- package/skills/stitch-a11y/SKILL.md +428 -0
- package/skills/stitch-a11y/resources/audit-checklist.md +102 -0
- package/skills/stitch-animate/SKILL.md +371 -0
- package/skills/stitch-animate/resources/animation-patterns.md +248 -0
- package/skills/stitch-design-md/SKILL.md +215 -0
- package/skills/stitch-design-md/examples/DESIGN.md +54 -0
- package/skills/stitch-design-md/examples/usage.md +67 -0
- package/skills/stitch-design-md/scripts/fetch-stitch.sh +35 -0
- package/skills/stitch-design-system/SKILL.md +314 -0
- package/skills/stitch-design-system/resources/tokens-template.css +237 -0
- package/skills/stitch-html-components/SKILL.md +344 -0
- package/skills/stitch-html-components/resources/architecture-checklist.md +74 -0
- package/skills/stitch-html-components/scripts/fetch-stitch.sh +45 -0
- package/skills/stitch-loop/SKILL.md +183 -0
- package/skills/stitch-loop/examples/SITE.md +39 -0
- package/skills/stitch-loop/examples/next-prompt.md +24 -0
- package/skills/stitch-loop/examples/usage.md +77 -0
- package/skills/stitch-mcp-apply-design-system/SKILL.md +82 -0
- package/skills/stitch-mcp-create-design-system/SKILL.md +117 -0
- package/skills/stitch-mcp-create-project/SKILL.md +77 -0
- package/skills/stitch-mcp-delete-project/SKILL.md +62 -0
- package/skills/stitch-mcp-edit-screens/SKILL.md +121 -0
- package/skills/stitch-mcp-generate-screen-from-text/SKILL.md +102 -0
- package/skills/stitch-mcp-generate-screen-from-text/examples/desktop.md +53 -0
- package/skills/stitch-mcp-generate-screen-from-text/examples/mobile.md +71 -0
- package/skills/stitch-mcp-generate-variants/SKILL.md +124 -0
- package/skills/stitch-mcp-get-project/SKILL.md +67 -0
- package/skills/stitch-mcp-get-screen/SKILL.md +117 -0
- package/skills/stitch-mcp-get-screen/scripts/fetch-stitch.sh +35 -0
- package/skills/stitch-mcp-list-design-systems/SKILL.md +84 -0
- package/skills/stitch-mcp-list-projects/SKILL.md +77 -0
- package/skills/stitch-mcp-list-screens/SKILL.md +69 -0
- package/skills/stitch-mcp-update-design-system/SKILL.md +82 -0
- package/skills/stitch-mcp-upload-screens-from-images/SKILL.md +95 -0
- package/skills/stitch-mcp-upload-screens-from-images/scripts/encode-image.sh +43 -0
- package/skills/stitch-nextjs-components/SKILL.md +181 -0
- package/skills/stitch-nextjs-components/resources/architecture-checklist.md +65 -0
- package/skills/stitch-nextjs-components/resources/component-template.tsx +101 -0
- package/skills/stitch-nextjs-components/scripts/fetch-stitch.sh +45 -0
- package/skills/stitch-orchestrator/SKILL.md +337 -0
- package/skills/stitch-orchestrator/examples/workflow.md +173 -0
- package/skills/stitch-react-components/SKILL.md +236 -0
- package/skills/stitch-react-components/references/tailwind-to-react.md +117 -0
- package/skills/stitch-react-components/resources/architecture-checklist.md +34 -0
- package/skills/stitch-react-components/resources/component-template.tsx +35 -0
- package/skills/stitch-react-components/scripts/fetch-stitch.sh +35 -0
- package/skills/stitch-react-native-components/SKILL.md +333 -0
- package/skills/stitch-react-native-components/resources/architecture-checklist.md +74 -0
- package/skills/stitch-react-native-components/resources/component-template.tsx +104 -0
- package/skills/stitch-react-native-components/scripts/fetch-stitch.sh +45 -0
- package/skills/stitch-remotion/SKILL.md +280 -0
- package/skills/stitch-setup/SKILL.md +183 -0
- package/skills/stitch-shadcn-ui/SKILL.md +255 -0
- package/skills/stitch-skill-creator/SKILL.md +257 -0
- package/skills/stitch-skill-creator/references/output-patterns.md +71 -0
- package/skills/stitch-skill-creator/scripts/init_stitch_skill.py +229 -0
- package/skills/stitch-svelte-components/SKILL.md +282 -0
- package/skills/stitch-svelte-components/resources/architecture-checklist.md +62 -0
- package/skills/stitch-svelte-components/resources/component-template.svelte +193 -0
- package/skills/stitch-svelte-components/scripts/fetch-stitch.sh +36 -0
- package/skills/stitch-swiftui-components/SKILL.md +424 -0
- package/skills/stitch-swiftui-components/resources/architecture-checklist.md +83 -0
- package/skills/stitch-swiftui-components/resources/component-template.swift +131 -0
- package/skills/stitch-swiftui-components/resources/layout-mapping.md +155 -0
- package/skills/stitch-swiftui-components/scripts/fetch-stitch.sh +45 -0
- package/skills/stitch-ued-guide/SKILL.md +124 -0
- package/skills/stitch-ui-design-spec-generator/SKILL.md +115 -0
- package/skills/stitch-ui-design-spec-generator/examples/usage.md +79 -0
- package/skills/stitch-ui-design-variants/SKILL.md +127 -0
- package/skills/stitch-ui-prompt-architect/SKILL.md +196 -0
- package/skills/stitch-ui-prompt-architect/references/KEYWORDS.md +170 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Stitch Skill Initializer — bootstraps a new stitch-kit skill from the standard template.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python3 init_stitch_skill.py <skill-name> --path <path>
|
|
7
|
+
|
|
8
|
+
Examples:
|
|
9
|
+
python3 init_stitch_skill.py ecommerce-architect --path skills/
|
|
10
|
+
# Creates: skills/stitch-ui-ecommerce-architect
|
|
11
|
+
|
|
12
|
+
python3 init_stitch_skill.py stitch-ui-blog-architect --path skills/
|
|
13
|
+
# Creates: skills/stitch-ui-blog-architect
|
|
14
|
+
|
|
15
|
+
python3 init_stitch_skill.py flutter-components --path skills/
|
|
16
|
+
# Creates: skills/stitch-flutter-components
|
|
17
|
+
|
|
18
|
+
Rules:
|
|
19
|
+
- Domain prompt architects: stitch-ui-[domain]-architect
|
|
20
|
+
- Framework conversion skills: stitch-[framework]-components
|
|
21
|
+
- Quality/analysis tools: stitch-[capability]
|
|
22
|
+
- MCP wrappers: stitch-mcp-[tool-name]
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import sys
|
|
26
|
+
import re
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
# ─── Templates ────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
SKILL_MD_TEMPLATE = """\
|
|
32
|
+
---
|
|
33
|
+
name: {skill_name}
|
|
34
|
+
description: [One clear sentence — when to use this skill and what it does.]
|
|
35
|
+
allowed-tools:
|
|
36
|
+
- "Read"
|
|
37
|
+
- "Write"
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# {scenario_title}
|
|
41
|
+
|
|
42
|
+
**Constraint:** Only use this skill when the user explicitly mentions "Stitch" [and any additional trigger condition].
|
|
43
|
+
|
|
44
|
+
[One sentence describing what this skill does.]
|
|
45
|
+
|
|
46
|
+
## When to use this skill vs. similar skills
|
|
47
|
+
|
|
48
|
+
| Skill | Use when |
|
|
49
|
+
|-------|---------|
|
|
50
|
+
| `{skill_name}` | [This skill's use case] |
|
|
51
|
+
| `[similar-skill]` | [The other skill's use case] |
|
|
52
|
+
|
|
53
|
+
## Prerequisites
|
|
54
|
+
|
|
55
|
+
- [What the user/environment needs before this skill can run]
|
|
56
|
+
|
|
57
|
+
## Step 1: [First step]
|
|
58
|
+
|
|
59
|
+
[Instructions]
|
|
60
|
+
|
|
61
|
+
## Step 2: [Core workflow]
|
|
62
|
+
|
|
63
|
+
[Instructions]
|
|
64
|
+
|
|
65
|
+
## Output
|
|
66
|
+
|
|
67
|
+
[What this skill produces]
|
|
68
|
+
|
|
69
|
+
## Troubleshooting
|
|
70
|
+
|
|
71
|
+
| Issue | Fix |
|
|
72
|
+
|-------|-----|
|
|
73
|
+
|
|
74
|
+
## References
|
|
75
|
+
|
|
76
|
+
- `examples/usage.md` — Worked examples
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
USAGE_MD_TEMPLATE = """\
|
|
80
|
+
# {scenario_title} — Usage Examples
|
|
81
|
+
|
|
82
|
+
## Example 1: [Scenario title]
|
|
83
|
+
|
|
84
|
+
**User:** "[Specific user request]"
|
|
85
|
+
|
|
86
|
+
**Skill activates because:** [Why this triggers the skill]
|
|
87
|
+
|
|
88
|
+
**What the skill does:**
|
|
89
|
+
1. [Step 1]
|
|
90
|
+
2. [Step 2]
|
|
91
|
+
|
|
92
|
+
**Output:**
|
|
93
|
+
[Description or snippet of what gets generated]
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Example 2: [Different scenario]
|
|
98
|
+
|
|
99
|
+
**User:** "[Another specific request]"
|
|
100
|
+
|
|
101
|
+
**Skill activates because:** [Reason]
|
|
102
|
+
|
|
103
|
+
**What the skill does:**
|
|
104
|
+
1. [Step 1]
|
|
105
|
+
2. [Step 2]
|
|
106
|
+
|
|
107
|
+
**Output:**
|
|
108
|
+
[Description or snippet]
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
ARCH_CHECKLIST_TEMPLATE = """\
|
|
112
|
+
# {scenario_title} — Architecture Checklist
|
|
113
|
+
|
|
114
|
+
Run through this before marking the task complete.
|
|
115
|
+
|
|
116
|
+
## Structure
|
|
117
|
+
- [ ] Components are in separate files
|
|
118
|
+
- [ ] No single monolithic output file
|
|
119
|
+
|
|
120
|
+
## Types
|
|
121
|
+
- [ ] No `any` types
|
|
122
|
+
- [ ] All props have typed interfaces
|
|
123
|
+
|
|
124
|
+
## Dark mode
|
|
125
|
+
- [ ] Theme tokens used everywhere — no hardcoded colors
|
|
126
|
+
|
|
127
|
+
## Accessibility
|
|
128
|
+
- [ ] All interactive elements are keyboard accessible
|
|
129
|
+
- [ ] Images have descriptive alt text
|
|
130
|
+
|
|
131
|
+
## Performance
|
|
132
|
+
- [ ] No `console.log` in production code
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
def normalize_skill_name(input_name: str) -> str:
|
|
138
|
+
"""
|
|
139
|
+
Ensures the skill follows stitch-kit naming conventions.
|
|
140
|
+
Adds stitch- prefix if missing.
|
|
141
|
+
Does NOT auto-add suffixes — the caller decides the full name.
|
|
142
|
+
"""
|
|
143
|
+
name = input_name.lower().strip()
|
|
144
|
+
if not name.startswith("stitch-"):
|
|
145
|
+
name = "stitch-" + name
|
|
146
|
+
return name
|
|
147
|
+
|
|
148
|
+
def to_title(skill_name: str) -> str:
|
|
149
|
+
"""
|
|
150
|
+
Converts 'stitch-ui-ecommerce-architect' → 'UI Ecommerce Architect'
|
|
151
|
+
"""
|
|
152
|
+
core = re.sub(r"^stitch-", "", skill_name)
|
|
153
|
+
return " ".join(word.capitalize() for word in core.split("-"))
|
|
154
|
+
|
|
155
|
+
def is_valid_name(name: str) -> bool:
|
|
156
|
+
"""Validates kebab-case, starts with stitch-, lowercase."""
|
|
157
|
+
return bool(re.fullmatch(r"stitch-[a-z0-9]+(?:-[a-z0-9]+)*", name))
|
|
158
|
+
|
|
159
|
+
# ─── Core logic ───────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
def init_skill(input_name: str, path: str) -> Path | None:
|
|
162
|
+
skill_name = normalize_skill_name(input_name)
|
|
163
|
+
scenario_title = to_title(skill_name)
|
|
164
|
+
skill_dir = Path(path).resolve() / skill_name
|
|
165
|
+
|
|
166
|
+
# Validation
|
|
167
|
+
if not is_valid_name(skill_name):
|
|
168
|
+
print(f"❌ Invalid skill name: {skill_name}")
|
|
169
|
+
print(" Expected kebab-case starting with 'stitch-'")
|
|
170
|
+
print(f" Examples: stitch-ui-ecommerce-architect, stitch-flutter-components")
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
if skill_dir.exists():
|
|
174
|
+
print(f"❌ Skill directory already exists: {skill_dir}")
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
# Create directories
|
|
178
|
+
try:
|
|
179
|
+
(skill_dir / "examples").mkdir(parents=True)
|
|
180
|
+
print(f"✅ Created: {skill_dir}/")
|
|
181
|
+
except Exception as e:
|
|
182
|
+
print(f"❌ Failed to create directory: {e}")
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
# Write SKILL.md
|
|
186
|
+
skill_content = SKILL_MD_TEMPLATE.format(
|
|
187
|
+
skill_name=skill_name,
|
|
188
|
+
scenario_title=scenario_title,
|
|
189
|
+
)
|
|
190
|
+
(skill_dir / "SKILL.md").write_text(skill_content)
|
|
191
|
+
print("✅ Created SKILL.md")
|
|
192
|
+
|
|
193
|
+
# Write examples/usage.md
|
|
194
|
+
usage_content = USAGE_MD_TEMPLATE.format(scenario_title=scenario_title)
|
|
195
|
+
(skill_dir / "examples" / "usage.md").write_text(usage_content)
|
|
196
|
+
print("✅ Created examples/usage.md")
|
|
197
|
+
|
|
198
|
+
# Print next steps
|
|
199
|
+
print(f"\n✅ Skill '{skill_name}' initialized.")
|
|
200
|
+
print("\nNext steps:")
|
|
201
|
+
print(f" 1. Edit {skill_dir}/SKILL.md — fill in description, steps, routing table")
|
|
202
|
+
print(f" 2. Edit {skill_dir}/examples/usage.md — replace placeholders with real examples")
|
|
203
|
+
print(f" 3. Add to .claude-plugin/marketplace.json in the right plugin group")
|
|
204
|
+
print(f" 4. Add row to docs/skills-index.md")
|
|
205
|
+
print(f" 5. Add row to README.md in the right layer table")
|
|
206
|
+
|
|
207
|
+
return skill_dir
|
|
208
|
+
|
|
209
|
+
# ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
def main():
|
|
212
|
+
if len(sys.argv) < 2:
|
|
213
|
+
print(__doc__)
|
|
214
|
+
sys.exit(1)
|
|
215
|
+
|
|
216
|
+
input_name = sys.argv[1]
|
|
217
|
+
path = "."
|
|
218
|
+
|
|
219
|
+
# Parse --path flag
|
|
220
|
+
for i, arg in enumerate(sys.argv[2:], start=2):
|
|
221
|
+
if arg == "--path" and i + 1 < len(sys.argv):
|
|
222
|
+
path = sys.argv[i + 1]
|
|
223
|
+
break
|
|
224
|
+
|
|
225
|
+
result = init_skill(input_name, path)
|
|
226
|
+
sys.exit(0 if result else 1)
|
|
227
|
+
|
|
228
|
+
if __name__ == "__main__":
|
|
229
|
+
main()
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stitch-svelte-components
|
|
3
|
+
description: Converts Stitch designs into Svelte 5 / SvelteKit components using the runes API — scoped CSS with custom properties, built-in transitions, TypeScript, dark mode, and accessible markup.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- "stitch*:*"
|
|
6
|
+
- "Bash"
|
|
7
|
+
- "Read"
|
|
8
|
+
- "Write"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Stitch → Svelte 5 / SvelteKit Components
|
|
12
|
+
|
|
13
|
+
You are a Svelte 5 engineer. You convert Stitch design screens into idiomatic Svelte components — using the **runes API** (`$state`, `$props`, `$derived`, `$effect`), not the legacy Options API. Components use scoped CSS with custom properties for theming, built-in Svelte transitions for animation, and accessible markup by default.
|
|
14
|
+
|
|
15
|
+
> **Note:** This is the only Stitch skill that targets Svelte. The official `react-components` skill targets Vite/React. Use this skill when the project uses SvelteKit.
|
|
16
|
+
|
|
17
|
+
## When to use this skill
|
|
18
|
+
|
|
19
|
+
Use this skill when:
|
|
20
|
+
- The target project uses **SvelteKit** or **Svelte 5** standalone
|
|
21
|
+
- You see `.svelte` files, `svelte.config.js`, or `+page.svelte` conventions
|
|
22
|
+
- The user mentions `svelte`, `sveltekit`, `$state`, `$props`, or `runes`
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
- Access to the Stitch MCP server
|
|
27
|
+
- A Stitch project with at least one generated screen
|
|
28
|
+
- Target project uses Svelte 5 (runes enabled) — check `package.json` for `"svelte": "^5"`
|
|
29
|
+
|
|
30
|
+
## Step 1: Retrieve the Stitch design
|
|
31
|
+
|
|
32
|
+
1. **Namespace discovery** — Run `list_tools` to find the Stitch MCP prefix. Use it for all subsequent calls.
|
|
33
|
+
2. **Fetch screen metadata** — Call `[prefix]:get_screen` to retrieve design JSON.
|
|
34
|
+
3. **Download HTML** — Use the reliable downloader:
|
|
35
|
+
```bash
|
|
36
|
+
bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html"
|
|
37
|
+
```
|
|
38
|
+
4. **Visual reference** — Check `screenshot.downloadUrl` before writing code.
|
|
39
|
+
|
|
40
|
+
## Step 2: SvelteKit file conventions
|
|
41
|
+
|
|
42
|
+
SvelteKit uses file-based routing. Map Stitch screens to this structure:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
src/
|
|
46
|
+
├── routes/
|
|
47
|
+
│ ├── +layout.svelte ← Persistent shell (nav, footer)
|
|
48
|
+
│ ├── +layout.ts ← Layout load function (optional)
|
|
49
|
+
│ ├── +page.svelte ← Route page component
|
|
50
|
+
│ ├── [route]/
|
|
51
|
+
│ │ ├── +page.svelte ← Sub-route page
|
|
52
|
+
│ │ └── +page.ts ← Page load function (server-side data)
|
|
53
|
+
├── lib/
|
|
54
|
+
│ ├── components/ ← Reusable components
|
|
55
|
+
│ │ └── [Name].svelte
|
|
56
|
+
│ ├── data/
|
|
57
|
+
│ │ └── mockData.ts ← Decoupled static content
|
|
58
|
+
│ └── types/
|
|
59
|
+
│ └── index.ts ← Shared types
|
|
60
|
+
static/ ← Static assets
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Key rules:**
|
|
64
|
+
- Pages live in `src/routes/` as `+page.svelte`
|
|
65
|
+
- Reusable components live in `src/lib/components/`
|
|
66
|
+
- Import `$lib/` is an alias for `src/lib/` — always use it
|
|
67
|
+
|
|
68
|
+
## Step 3: Svelte 5 runes API
|
|
69
|
+
|
|
70
|
+
**Use runes exclusively.** Never use the old `export let`, `let x = 0` reactive syntax, or `$:` labels.
|
|
71
|
+
|
|
72
|
+
### Props
|
|
73
|
+
```svelte
|
|
74
|
+
<script lang="ts">
|
|
75
|
+
interface Props {
|
|
76
|
+
title: string
|
|
77
|
+
description?: string
|
|
78
|
+
onAction?: () => void
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// $props() replaces export let
|
|
82
|
+
const { title, description = 'Default text', onAction }: Props = $props()
|
|
83
|
+
</script>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Reactive state
|
|
87
|
+
```svelte
|
|
88
|
+
<script lang="ts">
|
|
89
|
+
// $state() replaces let count = 0
|
|
90
|
+
let count = $state(0)
|
|
91
|
+
let isOpen = $state(false)
|
|
92
|
+
|
|
93
|
+
// $derived() replaces $: doubled = count * 2
|
|
94
|
+
const doubled = $derived(count * 2)
|
|
95
|
+
|
|
96
|
+
// $effect() replaces onMount / afterUpdate for side effects
|
|
97
|
+
$effect(() => {
|
|
98
|
+
console.log('count changed:', count)
|
|
99
|
+
})
|
|
100
|
+
</script>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Event handling
|
|
104
|
+
```svelte
|
|
105
|
+
<!-- Direct event attributes, no createEventDispatcher -->
|
|
106
|
+
<button onclick={() => count++}>Increment</button>
|
|
107
|
+
<button onclick={onAction}>Custom action</button>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Step 4: Scoped CSS with design tokens
|
|
111
|
+
|
|
112
|
+
Svelte scopes CSS to the component by default — use this aggressively. Map Stitch colors to custom properties in the `:root` (via `+layout.svelte` or `app.css`) and reference them in each component.
|
|
113
|
+
|
|
114
|
+
**In `src/app.css` (global):**
|
|
115
|
+
```css
|
|
116
|
+
:root {
|
|
117
|
+
--color-background: #ffffff;
|
|
118
|
+
--color-surface: #f4f4f5;
|
|
119
|
+
--color-primary: /* dominant color from Stitch design */;
|
|
120
|
+
--color-primary-foreground: #ffffff;
|
|
121
|
+
--color-text: #09090b;
|
|
122
|
+
--color-text-muted: #71717a;
|
|
123
|
+
--color-border: #e4e4e7;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
[data-theme='dark'] {
|
|
127
|
+
--color-background: #09090b;
|
|
128
|
+
--color-surface: #18181b;
|
|
129
|
+
--color-primary: /* same hue, adjusted for dark bg */;
|
|
130
|
+
--color-primary-foreground: #09090b;
|
|
131
|
+
--color-text: #fafafa;
|
|
132
|
+
--color-text-muted: #a1a1aa;
|
|
133
|
+
--color-border: #27272a;
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**In each component (scoped):**
|
|
138
|
+
```svelte
|
|
139
|
+
<style>
|
|
140
|
+
.card {
|
|
141
|
+
background-color: var(--color-surface);
|
|
142
|
+
border: 1px solid var(--color-border);
|
|
143
|
+
color: var(--color-text);
|
|
144
|
+
border-radius: 0.5rem;
|
|
145
|
+
padding: 1.5rem;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.card:hover {
|
|
149
|
+
/* Scoped — won't leak to parent or children */
|
|
150
|
+
border-color: var(--color-primary);
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Dark mode toggle** — Add a `$state` in `+layout.svelte`:
|
|
156
|
+
```svelte
|
|
157
|
+
<script lang="ts">
|
|
158
|
+
let theme = $state<'light' | 'dark'>('light')
|
|
159
|
+
|
|
160
|
+
function toggleTheme() {
|
|
161
|
+
theme = theme === 'light' ? 'dark' : 'light'
|
|
162
|
+
document.documentElement.setAttribute('data-theme', theme)
|
|
163
|
+
}
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<svelte:element this="div" data-theme={theme}>
|
|
167
|
+
{@render children()}
|
|
168
|
+
</svelte:element>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Step 5: Built-in transitions and animations
|
|
172
|
+
|
|
173
|
+
Svelte has first-class transition support. Apply these from the Stitch design intent:
|
|
174
|
+
|
|
175
|
+
```svelte
|
|
176
|
+
<script lang="ts">
|
|
177
|
+
import { fade, fly, slide, scale } from 'svelte/transition'
|
|
178
|
+
import { cubicOut } from 'svelte/easing'
|
|
179
|
+
|
|
180
|
+
let show = $state(false)
|
|
181
|
+
</script>
|
|
182
|
+
|
|
183
|
+
<!-- Page entry fade -->
|
|
184
|
+
<div transition:fade={{ duration: 200 }}>
|
|
185
|
+
Content that fades in
|
|
186
|
+
</div>
|
|
187
|
+
|
|
188
|
+
<!-- Slide panel -->
|
|
189
|
+
{#if isOpen}
|
|
190
|
+
<aside transition:fly={{ x: -300, duration: 300, easing: cubicOut }}>
|
|
191
|
+
Sidebar content
|
|
192
|
+
</aside>
|
|
193
|
+
{/if}
|
|
194
|
+
|
|
195
|
+
<!-- Collapsible section -->
|
|
196
|
+
{#if expanded}
|
|
197
|
+
<div transition:slide={{ duration: 200 }}>
|
|
198
|
+
Expandable content
|
|
199
|
+
</div>
|
|
200
|
+
{/if}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Always respect reduced motion:**
|
|
204
|
+
```svelte
|
|
205
|
+
<script lang="ts">
|
|
206
|
+
// Check user preference once
|
|
207
|
+
const prefersReducedMotion = $state(
|
|
208
|
+
typeof window !== 'undefined'
|
|
209
|
+
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
210
|
+
: false
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
// Conditionally disable transitions
|
|
214
|
+
const transitionOptions = $derived(
|
|
215
|
+
prefersReducedMotion ? {} : { duration: 200 }
|
|
216
|
+
)
|
|
217
|
+
</script>
|
|
218
|
+
|
|
219
|
+
<div transition:fade={transitionOptions}>...</div>
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Step 6: Accessibility in Svelte
|
|
223
|
+
|
|
224
|
+
Svelte's compiler warns about missing accessibility attributes — treat all compiler warnings as errors.
|
|
225
|
+
|
|
226
|
+
- **`role` and ARIA**: Add `role` when using non-semantic elements. Always pair with `aria-label` or `aria-labelledby`.
|
|
227
|
+
- **`bind:this`**: Use for programmatic focus management (e.g., focus trap in modals).
|
|
228
|
+
- **Keyboard handlers**: Any `onclick` handler on a non-interactive element needs `onkeydown`/`onkeyup` too, or use a `<button>`.
|
|
229
|
+
- **Screen reader text**: Use `class="sr-only"` (define in app.css) for visually hidden labels.
|
|
230
|
+
|
|
231
|
+
```svelte
|
|
232
|
+
<!-- Good: button with accessible label -->
|
|
233
|
+
<button
|
|
234
|
+
onclick={closeModal}
|
|
235
|
+
aria-label="Close dialog"
|
|
236
|
+
class="icon-btn"
|
|
237
|
+
>
|
|
238
|
+
<CloseIcon />
|
|
239
|
+
</button>
|
|
240
|
+
|
|
241
|
+
<!-- Good: Svelte dialog with focus trap -->
|
|
242
|
+
<dialog
|
|
243
|
+
bind:this={dialogEl}
|
|
244
|
+
aria-labelledby="dialog-title"
|
|
245
|
+
aria-modal="true"
|
|
246
|
+
>
|
|
247
|
+
<h2 id="dialog-title">{title}</h2>
|
|
248
|
+
</dialog>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Step 7: Execution steps
|
|
252
|
+
|
|
253
|
+
1. **Environment check** — If `node_modules` missing, run `npm install`.
|
|
254
|
+
2. **Data layer** — Create `src/lib/data/mockData.ts` from design content.
|
|
255
|
+
3. **Component drafting** — Use `resources/component-template.svelte` as base. Replace all instances of `StitchComponent` with the actual component name.
|
|
256
|
+
4. **CSS tokens** — Add color tokens to `src/app.css`. If using `stitch-design-system`, import its generated `design-tokens.css` instead.
|
|
257
|
+
5. **Wiring** — Update `src/routes/+page.svelte` to import and use the new components. Import from `$lib/components/`.
|
|
258
|
+
6. **Quality check** — Run through `resources/architecture-checklist.md`.
|
|
259
|
+
7. **Dev verification** — Run `npm run dev`. Toggle dark mode. Test keyboard navigation.
|
|
260
|
+
|
|
261
|
+
## Troubleshooting
|
|
262
|
+
|
|
263
|
+
| Issue | Fix |
|
|
264
|
+
|-------|-----|
|
|
265
|
+
| Runes syntax error | Confirm `svelte: ^5` in `package.json`. Old syntax is invalid in Svelte 5. |
|
|
266
|
+
| `$props()` type error | Add `lang="ts"` to `<script>` tag |
|
|
267
|
+
| CSS not scoped | Ensure styles are inside `<style>` block, not in a `.css` import |
|
|
268
|
+
| Transition not playing | Check `prefers-reduced-motion` isn't causing empty config |
|
|
269
|
+
| `$lib` not resolving | Confirm `"paths": {"$lib/*": ["src/lib/*"]}` in `tsconfig.json` |
|
|
270
|
+
| Dark mode flicker on load | Read theme from `localStorage` in a synchronous `<svelte:head>` script |
|
|
271
|
+
|
|
272
|
+
## Integration with other skills
|
|
273
|
+
|
|
274
|
+
- **stitch-design-system** — Run first to generate `design-tokens.css` for the CSS variable foundation.
|
|
275
|
+
- **stitch-animate** — Run after for Svelte-specific transition patterns beyond the basics above.
|
|
276
|
+
- **stitch-a11y** — Run after for a full accessibility audit when the design has complex UI patterns.
|
|
277
|
+
|
|
278
|
+
## References
|
|
279
|
+
|
|
280
|
+
- `resources/component-template.svelte` — Production-ready Svelte 5 component boilerplate
|
|
281
|
+
- `resources/architecture-checklist.md` — Pre-ship quality checklist
|
|
282
|
+
- `scripts/fetch-stitch.sh` — Reliable GCS HTML downloader
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Svelte Components — Architecture Checklist
|
|
2
|
+
|
|
3
|
+
Run through this before marking the task complete.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
- [ ] Components are in `src/lib/components/` — imported via `$lib/components/`
|
|
8
|
+
- [ ] Static/mock data is in `src/lib/data/mockData.ts`, not hardcoded in `.svelte` files
|
|
9
|
+
- [ ] Shared types are in `src/lib/types/index.ts`
|
|
10
|
+
- [ ] Pages are in `src/routes/` using `+page.svelte` convention
|
|
11
|
+
|
|
12
|
+
## Svelte 5 runes
|
|
13
|
+
|
|
14
|
+
- [ ] Props use `$props()`, NOT `export let`
|
|
15
|
+
- [ ] Reactive state uses `$state()`, NOT `let x = 0` with `$:` elsewhere
|
|
16
|
+
- [ ] Computed values use `$derived()`, NOT `$: computed = ...`
|
|
17
|
+
- [ ] Side effects use `$effect()`, NOT `onMount` / `afterUpdate` (unless lifecycle-specific)
|
|
18
|
+
- [ ] Event callbacks passed via props — no `createEventDispatcher`
|
|
19
|
+
- [ ] Snippets use `{@render children()}` syntax, NOT `<slot>`
|
|
20
|
+
|
|
21
|
+
## TypeScript
|
|
22
|
+
|
|
23
|
+
- [ ] `<script lang="ts">` on every component
|
|
24
|
+
- [ ] `Props` interface defined in the script block
|
|
25
|
+
- [ ] No `any` types
|
|
26
|
+
- [ ] `$lib` imports work (check `tsconfig.json` paths if not)
|
|
27
|
+
|
|
28
|
+
## Styling — scoped CSS + CSS variables
|
|
29
|
+
|
|
30
|
+
- [ ] All styles are in the component's `<style>` block (scoped by default)
|
|
31
|
+
- [ ] No hardcoded hex colors — all use `var(--color-*)` tokens
|
|
32
|
+
- [ ] Dark mode works — test with `[data-theme="dark"]` on `<html>`
|
|
33
|
+
- [ ] `design-tokens.css` imported in `src/app.css`
|
|
34
|
+
- [ ] `@media (prefers-reduced-motion: reduce)` overrides exist for any transitions
|
|
35
|
+
|
|
36
|
+
## Responsive
|
|
37
|
+
|
|
38
|
+
- [ ] Layout works at 320px (small mobile) — no horizontal overflow
|
|
39
|
+
- [ ] Layout works at 768px (tablet)
|
|
40
|
+
- [ ] Layout works at 1280px (desktop)
|
|
41
|
+
- [ ] `@media` breakpoints are inside the `<style>` block, not inline styles
|
|
42
|
+
|
|
43
|
+
## Accessibility baseline
|
|
44
|
+
|
|
45
|
+
- [ ] Semantic HTML: `<nav>`, `<main>`, `<section>`, `<article>` where appropriate
|
|
46
|
+
- [ ] All interactive elements are `<button>` or `<a>`, not `<div>` with `onclick`
|
|
47
|
+
- [ ] `<button>` elements have accessible labels (text or `aria-label`)
|
|
48
|
+
- [ ] Images have descriptive `alt` text (or `alt=""` + `aria-hidden="true"` for decorative)
|
|
49
|
+
- [ ] Svelte compiler a11y warnings treated as errors (not ignored)
|
|
50
|
+
- [ ] No `outline: none` without a `:focus-visible` replacement
|
|
51
|
+
|
|
52
|
+
## Transitions
|
|
53
|
+
|
|
54
|
+
- [ ] Svelte transitions are imported from `svelte/transition`
|
|
55
|
+
- [ ] `prefers-reduced-motion` is checked before applying IntersectionObserver animations
|
|
56
|
+
- [ ] Transitions don't cause layout shifts (use `opacity` + `transform`, not `height`/`width`)
|
|
57
|
+
|
|
58
|
+
## SvelteKit specifics
|
|
59
|
+
|
|
60
|
+
- [ ] `+page.svelte` imports from `$lib/`, not relative `../../`
|
|
61
|
+
- [ ] Data loading uses `+page.ts` load function, not `onMount` for initial data
|
|
62
|
+
- [ ] No hardcoded `window.*` calls at module level (SSR will break) — wrap in `$effect` or check `typeof window !== 'undefined'`
|