@archetypeai/ds-cli 0.3.7
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/LICENSE +21 -0
- package/README.md +123 -0
- package/bin.js +77 -0
- package/commands/add.js +42 -0
- package/commands/create.js +238 -0
- package/commands/init.js +199 -0
- package/files/AGENTS.md +63 -0
- package/files/CLAUDE.md +63 -0
- package/files/LICENSE +21 -0
- package/files/rules/accessibility.md +219 -0
- package/files/rules/charts.md +352 -0
- package/files/rules/components.md +267 -0
- package/files/rules/design-principles.md +56 -0
- package/files/rules/linting.md +31 -0
- package/files/rules/state.md +405 -0
- package/files/rules/styling.md +245 -0
- package/files/skills/apply-ds/SKILL.md +117 -0
- package/files/skills/apply-ds/scripts/setup.sh +271 -0
- package/files/skills/build-pattern/SKILL.md +202 -0
- package/files/skills/create-dashboard/SKILL.md +189 -0
- package/files/skills/deploy-worker/SKILL.md +231 -0
- package/files/skills/deploy-worker/references/wrangler-commands.md +327 -0
- package/files/skills/fix-accessibility/SKILL.md +184 -0
- package/files/skills/fix-metadata/SKILL.md +118 -0
- package/files/skills/fix-metadata/assets/favicon.ico +0 -0
- package/files/skills/setup-chart/SKILL.md +225 -0
- package/files/skills/setup-chart/data/embedding.csv +42 -0
- package/files/skills/setup-chart/data/timeseries.csv +173 -0
- package/files/skills/setup-chart/references/scatter-chart.md +229 -0
- package/files/skills/setup-chart/references/sensor-chart.md +156 -0
- package/lib/add-ds-config-codeagent.js +154 -0
- package/lib/add-ds-ui-svelte.js +93 -0
- package/lib/scaffold-ds-svelte-project.js +272 -0
- package/lib/use-package-manager.js +65 -0
- package/lib/use-shadcn-svelte-registry.js +26 -0
- package/lib/validate-url.js +31 -0
- package/package.json +34 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# Wrangler Command Reference
|
|
2
|
+
|
|
3
|
+
Full reference for wrangler CLI commands. Only load this when you need detailed command syntax beyond what's in SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Core Commands
|
|
6
|
+
|
|
7
|
+
| Task | Command |
|
|
8
|
+
| ------------------------- | --------------------------- |
|
|
9
|
+
| Start local dev server | `wrangler dev` |
|
|
10
|
+
| Deploy to Cloudflare | `wrangler deploy` |
|
|
11
|
+
| Deploy dry run | `wrangler deploy --dry-run` |
|
|
12
|
+
| Generate TypeScript types | `wrangler types` |
|
|
13
|
+
| Validate configuration | `wrangler check` |
|
|
14
|
+
| View live logs | `wrangler tail` |
|
|
15
|
+
| Delete Worker | `wrangler delete` |
|
|
16
|
+
| Auth status | `wrangler whoami` |
|
|
17
|
+
|
|
18
|
+
## Local Development
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Local mode (default) - uses local storage simulation
|
|
22
|
+
wrangler dev
|
|
23
|
+
|
|
24
|
+
# With specific environment
|
|
25
|
+
wrangler dev --env staging
|
|
26
|
+
|
|
27
|
+
# Custom port
|
|
28
|
+
wrangler dev --port 8787
|
|
29
|
+
|
|
30
|
+
# Live reload for HTML changes
|
|
31
|
+
wrangler dev --live-reload
|
|
32
|
+
|
|
33
|
+
# Test scheduled/cron handlers
|
|
34
|
+
wrangler dev --test-scheduled
|
|
35
|
+
# Then visit: http://localhost:8787/__scheduled
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Local Secrets
|
|
39
|
+
|
|
40
|
+
Create `.dev.vars` for local development secrets:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
API_KEY=local-dev-key
|
|
44
|
+
DATABASE_URL=postgres://localhost:5432/dev
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Deployment
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Deploy to production
|
|
51
|
+
wrangler deploy
|
|
52
|
+
|
|
53
|
+
# Deploy specific environment
|
|
54
|
+
wrangler deploy --env staging
|
|
55
|
+
|
|
56
|
+
# Dry run (validate without deploying)
|
|
57
|
+
wrangler deploy --dry-run
|
|
58
|
+
|
|
59
|
+
# Keep dashboard-set variables
|
|
60
|
+
wrangler deploy --keep-vars
|
|
61
|
+
|
|
62
|
+
# Minify code
|
|
63
|
+
wrangler deploy --minify
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Manage Secrets
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# Set secret interactively
|
|
70
|
+
wrangler secret put API_KEY
|
|
71
|
+
|
|
72
|
+
# Set from stdin
|
|
73
|
+
echo "secret-value" | wrangler secret put API_KEY
|
|
74
|
+
|
|
75
|
+
# List secrets
|
|
76
|
+
wrangler secret list
|
|
77
|
+
|
|
78
|
+
# Delete secret
|
|
79
|
+
wrangler secret delete API_KEY
|
|
80
|
+
|
|
81
|
+
# Bulk secrets from JSON file
|
|
82
|
+
wrangler secret bulk secrets.json
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Versions and Rollback
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# List recent versions
|
|
89
|
+
wrangler versions list
|
|
90
|
+
|
|
91
|
+
# Rollback to previous version
|
|
92
|
+
wrangler rollback
|
|
93
|
+
|
|
94
|
+
# Rollback to specific version
|
|
95
|
+
wrangler rollback <VERSION_ID>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## KV (Key-Value Store)
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Create namespace
|
|
102
|
+
wrangler kv namespace create MY_KV
|
|
103
|
+
|
|
104
|
+
# List namespaces
|
|
105
|
+
wrangler kv namespace list
|
|
106
|
+
|
|
107
|
+
# Put/get/delete values
|
|
108
|
+
wrangler kv key put --namespace-id <ID> "key" "value"
|
|
109
|
+
wrangler kv key get --namespace-id <ID> "key"
|
|
110
|
+
wrangler kv key delete --namespace-id <ID> "key"
|
|
111
|
+
|
|
112
|
+
# Bulk put from JSON
|
|
113
|
+
wrangler kv bulk put --namespace-id <ID> data.json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Config binding:
|
|
117
|
+
|
|
118
|
+
```jsonc
|
|
119
|
+
{ "kv_namespaces": [{ "binding": "CACHE", "id": "<NAMESPACE_ID>" }] }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## R2 (Object Storage)
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Create bucket
|
|
126
|
+
wrangler r2 bucket create my-bucket
|
|
127
|
+
|
|
128
|
+
# Upload/download/delete objects
|
|
129
|
+
wrangler r2 object put my-bucket/path/file.txt --file ./local-file.txt
|
|
130
|
+
wrangler r2 object get my-bucket/path/file.txt
|
|
131
|
+
wrangler r2 object delete my-bucket/path/file.txt
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Config binding:
|
|
135
|
+
|
|
136
|
+
```jsonc
|
|
137
|
+
{ "r2_buckets": [{ "binding": "ASSETS", "bucket_name": "my-bucket" }] }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## D1 (SQL Database)
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Create database
|
|
144
|
+
wrangler d1 create my-database
|
|
145
|
+
|
|
146
|
+
# Execute SQL
|
|
147
|
+
wrangler d1 execute my-database --remote --command "SELECT * FROM users"
|
|
148
|
+
wrangler d1 execute my-database --remote --file ./schema.sql
|
|
149
|
+
|
|
150
|
+
# Migrations
|
|
151
|
+
wrangler d1 migrations create my-database create_users_table
|
|
152
|
+
wrangler d1 migrations apply my-database --remote
|
|
153
|
+
|
|
154
|
+
# Export
|
|
155
|
+
wrangler d1 export my-database --remote --output backup.sql
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Config binding:
|
|
159
|
+
|
|
160
|
+
```jsonc
|
|
161
|
+
{ "d1_databases": [{ "binding": "DB", "database_name": "my-db", "database_id": "<DB_ID>" }] }
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Vectorize
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
wrangler vectorize create my-index --dimensions 768 --metric cosine
|
|
168
|
+
wrangler vectorize insert my-index --file vectors.ndjson
|
|
169
|
+
wrangler vectorize query my-index --vector "[0.1, 0.2, ...]" --top-k 10
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Config binding:
|
|
173
|
+
|
|
174
|
+
```jsonc
|
|
175
|
+
{ "vectorize": [{ "binding": "INDEX", "index_name": "my-index" }] }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Hyperdrive
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
wrangler hyperdrive create my-hyperdrive \
|
|
182
|
+
--connection-string "postgres://user:pass@host:5432/database"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Config binding:
|
|
186
|
+
|
|
187
|
+
```jsonc
|
|
188
|
+
{
|
|
189
|
+
"compatibility_flags": ["nodejs_compat_v2"],
|
|
190
|
+
"hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<HYPERDRIVE_ID>" }]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Workers AI
|
|
195
|
+
|
|
196
|
+
Config binding:
|
|
197
|
+
|
|
198
|
+
```jsonc
|
|
199
|
+
{ "ai": { "binding": "AI" } }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Workers AI always runs remotely and incurs usage charges even in local dev.
|
|
203
|
+
|
|
204
|
+
## Queues
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
wrangler queues create my-queue
|
|
208
|
+
wrangler queues consumer add my-queue my-worker
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Config binding:
|
|
212
|
+
|
|
213
|
+
```jsonc
|
|
214
|
+
{
|
|
215
|
+
"queues": {
|
|
216
|
+
"producers": [{ "binding": "MY_QUEUE", "queue": "my-queue" }],
|
|
217
|
+
"consumers": [{ "queue": "my-queue", "max_batch_size": 10 }]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Containers
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
wrangler containers build -t my-app:latest . --push
|
|
226
|
+
wrangler containers list
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Workflows
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
wrangler workflows trigger my-workflow --params '{"key": "value"}'
|
|
233
|
+
wrangler workflows instances list my-workflow
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Config binding:
|
|
237
|
+
|
|
238
|
+
```jsonc
|
|
239
|
+
{ "workflows": [{ "binding": "MY_WORKFLOW", "name": "my-workflow", "class_name": "MyWorkflow" }] }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Pipelines
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
wrangler pipelines create my-pipeline --r2 my-bucket
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Config binding:
|
|
249
|
+
|
|
250
|
+
```jsonc
|
|
251
|
+
{ "pipelines": [{ "binding": "MY_PIPELINE", "pipeline": "my-pipeline" }] }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Secrets Store
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
wrangler secrets-store store create my-store
|
|
258
|
+
wrangler secrets-store secret put <STORE_ID> my-secret
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Config binding:
|
|
262
|
+
|
|
263
|
+
```jsonc
|
|
264
|
+
{
|
|
265
|
+
"secrets_store_secrets": [
|
|
266
|
+
{ "binding": "MY_SECRET", "store_id": "<STORE_ID>", "secret_name": "my-secret" }
|
|
267
|
+
]
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Pages (Frontend Deployment)
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
wrangler pages project create my-site
|
|
275
|
+
wrangler pages deploy ./dist
|
|
276
|
+
wrangler pages deploy ./dist --branch main
|
|
277
|
+
wrangler pages deployment list --project-name my-site
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Observability
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Stream live logs
|
|
284
|
+
wrangler tail
|
|
285
|
+
wrangler tail --status error
|
|
286
|
+
wrangler tail --search "error"
|
|
287
|
+
wrangler tail --format json
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Config:
|
|
291
|
+
|
|
292
|
+
```jsonc
|
|
293
|
+
{ "observability": { "enabled": true, "head_sampling_rate": 1 } }
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Testing with Vitest
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
npm install -D @cloudflare/vitest-pool-workers vitest
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
`vitest.config.ts`:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
import { defineWorkersConfig } from '@cloudflare/vitest-pool-workers/config';
|
|
306
|
+
|
|
307
|
+
export default defineWorkersConfig({
|
|
308
|
+
test: {
|
|
309
|
+
poolOptions: {
|
|
310
|
+
workers: {
|
|
311
|
+
wrangler: { configPath: './wrangler.jsonc' }
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Troubleshooting
|
|
319
|
+
|
|
320
|
+
| Issue | Solution |
|
|
321
|
+
| ------------------------------- | ------------------------------------------ |
|
|
322
|
+
| `command not found: wrangler` | `npm install -D wrangler` |
|
|
323
|
+
| Auth errors | `wrangler login` |
|
|
324
|
+
| Config validation errors | `wrangler check` |
|
|
325
|
+
| Type errors after config change | `wrangler types` |
|
|
326
|
+
| Local storage not persisting | Check `.wrangler/state` directory |
|
|
327
|
+
| Binding undefined in Worker | Verify binding name matches config exactly |
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fix-accessibility
|
|
3
|
+
description: Audits and fixes accessibility issues in projects using shadcn-svelte and the Archetype AI design system. Use when running an a11y audit, fixing WCAG violations, adding aria labels, improving keyboard navigation, fixing focus management, adding screen reader support, or when the user mentions "accessibility", "a11y", "aria", "screen reader", or "keyboard navigation".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fixing Accessibility
|
|
7
|
+
|
|
8
|
+
Audit and fix accessibility issues in projects built with the design system.
|
|
9
|
+
|
|
10
|
+
## Audit Process
|
|
11
|
+
|
|
12
|
+
Walk through the project in this order:
|
|
13
|
+
|
|
14
|
+
1. **Icon-only buttons** — search for `<Button size="icon"` and similar patterns, verify each has `aria-label`
|
|
15
|
+
2. **Decorative icons** — icons next to text labels should have `aria-hidden="true"`
|
|
16
|
+
3. **Form inputs** — verify `aria-invalid` support for error states
|
|
17
|
+
4. **Focus rings** — confirm all interactive elements have `focus-visible:ring-*` styles
|
|
18
|
+
5. **Disabled states** — check `disabled:pointer-events-none disabled:opacity-50`
|
|
19
|
+
6. **Lists and groups** — verify `role="list"`, `role="listitem"`, `role="group"` where appropriate
|
|
20
|
+
7. **Screen reader text** — add `sr-only` spans where visual context is missing
|
|
21
|
+
8. **Keyboard navigation** — tab through the entire UI, verify all controls are reachable
|
|
22
|
+
9. **Dialog focus traps** — open dialogs, confirm focus is trapped and Escape closes them
|
|
23
|
+
|
|
24
|
+
## Common Issues and Fixes
|
|
25
|
+
|
|
26
|
+
### Icon-Only Buttons Missing aria-label
|
|
27
|
+
|
|
28
|
+
```svelte
|
|
29
|
+
<!-- Before -->
|
|
30
|
+
<Button size="icon">
|
|
31
|
+
<SearchIcon />
|
|
32
|
+
</Button>
|
|
33
|
+
|
|
34
|
+
<!-- After -->
|
|
35
|
+
<Button size="icon" aria-label="Search">
|
|
36
|
+
<SearchIcon />
|
|
37
|
+
</Button>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Decorative Icons Missing aria-hidden
|
|
41
|
+
|
|
42
|
+
Icons next to visible text labels are decorative and should be hidden from screen readers:
|
|
43
|
+
|
|
44
|
+
```svelte
|
|
45
|
+
<!-- Before -->
|
|
46
|
+
<Button>
|
|
47
|
+
<PlusIcon />
|
|
48
|
+
Add Item
|
|
49
|
+
</Button>
|
|
50
|
+
|
|
51
|
+
<!-- After -->
|
|
52
|
+
<Button>
|
|
53
|
+
<PlusIcon aria-hidden="true" />
|
|
54
|
+
Add Item
|
|
55
|
+
</Button>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Inputs Missing aria-invalid
|
|
59
|
+
|
|
60
|
+
Form inputs should reflect validation state:
|
|
61
|
+
|
|
62
|
+
```svelte
|
|
63
|
+
<!-- Before -->
|
|
64
|
+
<Input class={errors.email ? 'border-destructive' : ''} />
|
|
65
|
+
|
|
66
|
+
<!-- After -->
|
|
67
|
+
<Input aria-invalid={errors.email ? true : undefined} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The design system primitives already style `aria-invalid` with destructive border and ring colors — no extra classes needed.
|
|
71
|
+
|
|
72
|
+
### Missing Focus Ring Styles
|
|
73
|
+
|
|
74
|
+
Interactive elements must have visible focus indicators:
|
|
75
|
+
|
|
76
|
+
```svelte
|
|
77
|
+
<button
|
|
78
|
+
class={cn(
|
|
79
|
+
'outline-none',
|
|
80
|
+
'focus-visible:border-ring',
|
|
81
|
+
'focus-visible:ring-ring/50',
|
|
82
|
+
'focus-visible:ring-[3px]'
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Design system primitives include these by default. Custom interactive elements must add them manually.
|
|
88
|
+
|
|
89
|
+
### Disabled States Not Preventing Interaction
|
|
90
|
+
|
|
91
|
+
```svelte
|
|
92
|
+
<!-- For native elements -->
|
|
93
|
+
<button
|
|
94
|
+
class="disabled:pointer-events-none disabled:opacity-50"
|
|
95
|
+
disabled={isDisabled}
|
|
96
|
+
>
|
|
97
|
+
|
|
98
|
+
<!-- For links styled as buttons -->
|
|
99
|
+
<a
|
|
100
|
+
href={disabled ? undefined : href}
|
|
101
|
+
aria-disabled={disabled}
|
|
102
|
+
tabindex={disabled ? -1 : undefined}
|
|
103
|
+
class="aria-disabled:pointer-events-none aria-disabled:opacity-50"
|
|
104
|
+
>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Missing Roles on Lists and Groups
|
|
108
|
+
|
|
109
|
+
```svelte
|
|
110
|
+
<!-- Lists -->
|
|
111
|
+
<div role="list">
|
|
112
|
+
{#each items as item}
|
|
113
|
+
<div role="listitem">{item}</div>
|
|
114
|
+
{/each}
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<!-- Button groups -->
|
|
118
|
+
<div role="group" aria-label="Text formatting">
|
|
119
|
+
<Button>Bold</Button>
|
|
120
|
+
<Button>Italic</Button>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<!-- Loading indicators -->
|
|
124
|
+
<svg role="status" aria-label="Loading" class="animate-spin">...</svg>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Missing Screen Reader Text
|
|
128
|
+
|
|
129
|
+
Add visually hidden text where icons or visual cues carry meaning:
|
|
130
|
+
|
|
131
|
+
```svelte
|
|
132
|
+
<button>
|
|
133
|
+
<XIcon />
|
|
134
|
+
<span class="sr-only">Close</span>
|
|
135
|
+
</button>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Keyboard Navigation for Custom Elements
|
|
139
|
+
|
|
140
|
+
When building custom interactive elements (not using bits-ui primitives), ensure keyboard support:
|
|
141
|
+
|
|
142
|
+
```svelte
|
|
143
|
+
<div
|
|
144
|
+
role="button"
|
|
145
|
+
tabindex="0"
|
|
146
|
+
onkeydown={(e) => {
|
|
147
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
handleClick();
|
|
150
|
+
}
|
|
151
|
+
}}
|
|
152
|
+
onclick={handleClick}
|
|
153
|
+
>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Dialog and Popover Focus Traps
|
|
157
|
+
|
|
158
|
+
bits-ui handles focus trapping automatically for Dialog, Popover, Command, and Select. Verify:
|
|
159
|
+
|
|
160
|
+
- Focus moves into the dialog when opened
|
|
161
|
+
- Tab cycles within the dialog (does not escape)
|
|
162
|
+
- Escape closes the dialog
|
|
163
|
+
- Focus returns to the trigger element after close
|
|
164
|
+
|
|
165
|
+
If focus trapping is broken, check that the bits-ui primitive is used correctly and not wrapped in a way that breaks the DOM structure.
|
|
166
|
+
|
|
167
|
+
## Verification Checklist
|
|
168
|
+
|
|
169
|
+
After fixing, walk through the project and confirm:
|
|
170
|
+
|
|
171
|
+
- [ ] All icon-only buttons have `aria-label`
|
|
172
|
+
- [ ] All decorative icons have `aria-hidden="true"`
|
|
173
|
+
- [ ] Form inputs support `aria-invalid` styling
|
|
174
|
+
- [ ] All interactive elements have visible focus rings
|
|
175
|
+
- [ ] Disabled states prevent interaction and reduce opacity
|
|
176
|
+
- [ ] Loading indicators use `role="status"`
|
|
177
|
+
- [ ] Lists use `role="list"` and `role="listitem"`
|
|
178
|
+
- [ ] Groups use `role="group"` with `aria-label`
|
|
179
|
+
- [ ] Tab navigation reaches all interactive elements
|
|
180
|
+
- [ ] Dialogs trap focus and close with Escape
|
|
181
|
+
|
|
182
|
+
## Reference
|
|
183
|
+
|
|
184
|
+
See `@rules/accessibility.md` for the complete accessibility rules and patterns.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fix-metadata
|
|
3
|
+
description: Updates a SvelteKit project's metadata including page titles, favicons, meta descriptions, Open Graph tags, and SEO tags. Use when updating the favicon, setting page titles, adding OG tags, fixing SEO metadata, branding a project's tab/title, or when the user mentions "metadata", "favicon", "page title", "OG tags", or "SEO".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Fixing Metadata
|
|
7
|
+
|
|
8
|
+
Update page titles, favicons, and meta tags in SvelteKit projects using the design system.
|
|
9
|
+
|
|
10
|
+
## Where Metadata Lives
|
|
11
|
+
|
|
12
|
+
| Location | What goes there |
|
|
13
|
+
| ---------------------------- | ---------------------------------------------------------------- |
|
|
14
|
+
| `src/app.html` | Favicon `<link>`, charset, viewport, base HTML |
|
|
15
|
+
| `src/routes/+layout.svelte` | Global `<svelte:head>` for site-wide title, description, OG tags |
|
|
16
|
+
| `src/routes/**/+page.svelte` | Per-route `<svelte:head>` for page-specific titles |
|
|
17
|
+
|
|
18
|
+
## Favicon
|
|
19
|
+
|
|
20
|
+
### Install the ATAI Favicon
|
|
21
|
+
|
|
22
|
+
This skill ships with the default Archetype AI favicon in `assets/favicon.ico`. Copy it to the project:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
cp assets/favicon.ico static/favicon.ico
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Update app.html
|
|
29
|
+
|
|
30
|
+
Ensure `src/app.html` references the favicon:
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<!doctype html>
|
|
34
|
+
<html lang="en" class="dark">
|
|
35
|
+
<head>
|
|
36
|
+
<meta charset="utf-8" />
|
|
37
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
38
|
+
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
|
|
39
|
+
%sveltekit.head%
|
|
40
|
+
</head>
|
|
41
|
+
<body data-sveltekit-prerender="true">
|
|
42
|
+
<div style="display: contents">%sveltekit.body%</div>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
For SVG favicons (sharper at all sizes):
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<link rel="icon" href="%sveltekit.assets%/favicon.svg" type="image/svg+xml" />
|
|
51
|
+
<link rel="icon" href="%sveltekit.assets%/favicon.ico" sizes="any" />
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Page Title and Description
|
|
55
|
+
|
|
56
|
+
Add a global `<svelte:head>` in the root layout:
|
|
57
|
+
|
|
58
|
+
```svelte
|
|
59
|
+
<!-- src/routes/+layout.svelte -->
|
|
60
|
+
<script>
|
|
61
|
+
let { children } = $props();
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<svelte:head>
|
|
65
|
+
<title>My App — Archetype AI</title>
|
|
66
|
+
<meta name="description" content="Brief description of the application." />
|
|
67
|
+
</svelte:head>
|
|
68
|
+
|
|
69
|
+
{@render children?.()}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Open Graph Tags
|
|
73
|
+
|
|
74
|
+
Add OG tags for social sharing previews:
|
|
75
|
+
|
|
76
|
+
```svelte
|
|
77
|
+
<svelte:head>
|
|
78
|
+
<title>My App — Archetype AI</title>
|
|
79
|
+
<meta name="description" content="Brief description of the application." />
|
|
80
|
+
|
|
81
|
+
<!-- Open Graph -->
|
|
82
|
+
<meta property="og:title" content="My App — Archetype AI" />
|
|
83
|
+
<meta property="og:description" content="Brief description of the application." />
|
|
84
|
+
<meta property="og:type" content="website" />
|
|
85
|
+
<meta property="og:image" content="https://example.com/og-image.png" />
|
|
86
|
+
<meta property="og:url" content="https://example.com" />
|
|
87
|
+
|
|
88
|
+
<!-- Twitter Card -->
|
|
89
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
90
|
+
<meta name="twitter:title" content="My App — Archetype AI" />
|
|
91
|
+
<meta name="twitter:description" content="Brief description of the application." />
|
|
92
|
+
<meta name="twitter:image" content="https://example.com/og-image.png" />
|
|
93
|
+
</svelte:head>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Per-Route Metadata
|
|
97
|
+
|
|
98
|
+
Override the global title on specific pages:
|
|
99
|
+
|
|
100
|
+
```svelte
|
|
101
|
+
<!-- src/routes/dashboard/+page.svelte -->
|
|
102
|
+
<svelte:head>
|
|
103
|
+
<title>Dashboard — My App</title>
|
|
104
|
+
</svelte:head>
|
|
105
|
+
|
|
106
|
+
<!-- page content -->
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
SvelteKit merges `<svelte:head>` from layouts and pages — the most specific (page-level) wins for duplicate tags like `<title>`.
|
|
110
|
+
|
|
111
|
+
## Verification
|
|
112
|
+
|
|
113
|
+
- [ ] `static/favicon.ico` exists and is the ATAI favicon
|
|
114
|
+
- [ ] `app.html` has `<link rel="icon">` pointing to the favicon
|
|
115
|
+
- [ ] Root layout has `<svelte:head>` with title and description
|
|
116
|
+
- [ ] OG tags are present if social sharing is needed
|
|
117
|
+
- [ ] Per-route pages override title where appropriate
|
|
118
|
+
- [ ] Browser tab shows the correct favicon and title
|
|
Binary file
|