@getcoherent/cli 0.6.9 → 0.6.11
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.
|
@@ -194,48 +194,172 @@ NEVER include app-style elements (sidebar widgets, data tables, filters) on mark
|
|
|
194
194
|
var DESIGN_QUALITY_APP = `
|
|
195
195
|
## DESIGN QUALITY \u2014 APP PAGES
|
|
196
196
|
|
|
197
|
+
### Reference Patterns (COPY these exact patterns)
|
|
198
|
+
|
|
199
|
+
PAGE HEADER:
|
|
200
|
+
\`\`\`
|
|
201
|
+
<div className="flex items-center justify-between">
|
|
202
|
+
<div className="space-y-1">
|
|
203
|
+
<h1 className="text-2xl font-bold tracking-tight">Page Title</h1>
|
|
204
|
+
<p className="text-sm text-muted-foreground">Page description</p>
|
|
205
|
+
</div>
|
|
206
|
+
<Button><Plus className="size-4 mr-2 shrink-0" />New Item</Button>
|
|
207
|
+
</div>
|
|
208
|
+
\`\`\`
|
|
209
|
+
|
|
210
|
+
FILTER TOOLBAR (search + dropdowns + action):
|
|
211
|
+
\`\`\`
|
|
212
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
213
|
+
<div className="relative flex-1">
|
|
214
|
+
<Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground shrink-0" />
|
|
215
|
+
<Input placeholder="Search..." className="pl-9" />
|
|
216
|
+
</div>
|
|
217
|
+
<Select>
|
|
218
|
+
<SelectTrigger className="w-[180px]">
|
|
219
|
+
<SelectValue placeholder="All Status" />
|
|
220
|
+
</SelectTrigger>
|
|
221
|
+
<SelectContent>
|
|
222
|
+
<SelectItem value="all">All Status</SelectItem>
|
|
223
|
+
<SelectItem value="active">Active</SelectItem>
|
|
224
|
+
</SelectContent>
|
|
225
|
+
</Select>
|
|
226
|
+
<Button><Plus className="size-4 mr-2 shrink-0" />New Item</Button>
|
|
227
|
+
</div>
|
|
228
|
+
\`\`\`
|
|
229
|
+
CRITICAL: NEVER use <Select> with native <option> elements. Always use the shadcn compound pattern above (SelectTrigger + SelectValue + SelectContent + SelectItem).
|
|
230
|
+
Do NOT add standalone filter icon buttons. The Select dropdowns ARE the filters.
|
|
231
|
+
|
|
232
|
+
STATS GRID:
|
|
233
|
+
\`\`\`
|
|
234
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
235
|
+
<Card>
|
|
236
|
+
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
|
237
|
+
<CardTitle className="text-sm font-medium">Metric Name</CardTitle>
|
|
238
|
+
<TrendingUp className="size-4 text-muted-foreground shrink-0" />
|
|
239
|
+
</CardHeader>
|
|
240
|
+
<CardContent>
|
|
241
|
+
<div className="text-2xl font-bold">1,234</div>
|
|
242
|
+
<p className="text-xs text-muted-foreground">+12% from last month</p>
|
|
243
|
+
</CardContent>
|
|
244
|
+
</Card>
|
|
245
|
+
</div>
|
|
246
|
+
\`\`\`
|
|
247
|
+
|
|
248
|
+
DATA TABLE:
|
|
249
|
+
\`\`\`
|
|
250
|
+
<div className="overflow-x-auto">
|
|
251
|
+
<Table>
|
|
252
|
+
<TableHeader>
|
|
253
|
+
<TableRow>
|
|
254
|
+
<TableHead>Name</TableHead>
|
|
255
|
+
<TableHead>Status</TableHead>
|
|
256
|
+
<TableHead className="w-[50px]"></TableHead>
|
|
257
|
+
</TableRow>
|
|
258
|
+
</TableHeader>
|
|
259
|
+
<TableBody>
|
|
260
|
+
<TableRow className="hover:bg-muted/50">
|
|
261
|
+
<TableCell className="font-medium">Item name</TableCell>
|
|
262
|
+
<TableCell><Badge variant="default">Active</Badge></TableCell>
|
|
263
|
+
<TableCell>
|
|
264
|
+
<DropdownMenu>
|
|
265
|
+
<DropdownMenuTrigger asChild>
|
|
266
|
+
<Button variant="ghost" size="icon"><MoreHorizontal className="size-4 shrink-0" /></Button>
|
|
267
|
+
</DropdownMenuTrigger>
|
|
268
|
+
<DropdownMenuContent align="end">
|
|
269
|
+
<DropdownMenuItem>Edit</DropdownMenuItem>
|
|
270
|
+
<DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
|
|
271
|
+
</DropdownMenuContent>
|
|
272
|
+
</DropdownMenu>
|
|
273
|
+
</TableCell>
|
|
274
|
+
</TableRow>
|
|
275
|
+
</TableBody>
|
|
276
|
+
</Table>
|
|
277
|
+
</div>
|
|
278
|
+
\`\`\`
|
|
279
|
+
|
|
280
|
+
EMPTY STATE (when list/table has zero items):
|
|
281
|
+
\`\`\`
|
|
282
|
+
<div className="flex flex-col items-center justify-center py-12 text-center">
|
|
283
|
+
<Inbox className="size-12 text-muted-foreground mb-4 shrink-0" />
|
|
284
|
+
<h3 className="text-lg font-semibold">No items yet</h3>
|
|
285
|
+
<p className="text-sm text-muted-foreground mt-1 max-w-sm">Create your first item to get started.</p>
|
|
286
|
+
<Button className="mt-4"><Plus className="size-4 mr-2 shrink-0" />Create Item</Button>
|
|
287
|
+
</div>
|
|
288
|
+
\`\`\`
|
|
289
|
+
|
|
290
|
+
DATA CARD GRID:
|
|
291
|
+
\`\`\`
|
|
292
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
293
|
+
<Card className="hover:border-border/30 transition-colors">
|
|
294
|
+
<CardHeader className="flex flex-row items-start justify-between space-y-0">
|
|
295
|
+
<div className="space-y-1">
|
|
296
|
+
<CardTitle>Item Name</CardTitle>
|
|
297
|
+
<p className="text-sm text-muted-foreground">Description</p>
|
|
298
|
+
</div>
|
|
299
|
+
<DropdownMenu>
|
|
300
|
+
<DropdownMenuTrigger asChild>
|
|
301
|
+
<Button variant="ghost" size="icon"><MoreHorizontal className="size-4 shrink-0" /></Button>
|
|
302
|
+
</DropdownMenuTrigger>
|
|
303
|
+
<DropdownMenuContent align="end">
|
|
304
|
+
<DropdownMenuItem>Edit</DropdownMenuItem>
|
|
305
|
+
<DropdownMenuItem className="text-destructive">Delete</DropdownMenuItem>
|
|
306
|
+
</DropdownMenuContent>
|
|
307
|
+
</DropdownMenu>
|
|
308
|
+
</CardHeader>
|
|
309
|
+
<CardContent>...</CardContent>
|
|
310
|
+
</Card>
|
|
311
|
+
</div>
|
|
312
|
+
\`\`\`
|
|
313
|
+
|
|
197
314
|
### Spacing
|
|
198
315
|
- gap-4 md:gap-6 between sections
|
|
199
316
|
- p-4 lg:p-6 content padding
|
|
200
|
-
- Within cards: p-4 to p-6 (compact)
|
|
201
|
-
- Between cards in grid: gap-4 (tight)
|
|
202
|
-
|
|
203
|
-
### Layout
|
|
204
|
-
- Data tables, card grids, filters, stat rows
|
|
205
317
|
- Page wrapper: flex flex-1 flex-col gap-4 p-4 lg:p-6
|
|
206
|
-
- Stats grid: grid gap-4 md:grid-cols-2 lg:grid-cols-4
|
|
207
|
-
- Content: functional, scannable, data-dense
|
|
208
|
-
|
|
209
|
-
### Toolbars & Filters
|
|
210
|
-
- Filter row: flex flex-wrap items-center gap-2 (plain div, NOT inside a Card)
|
|
211
|
-
- Search input: MUST use flex-1 to fill remaining horizontal space. NEVER fixed-width search.
|
|
212
|
-
- Filters/selects: fixed width (w-[180px] or auto), do NOT flex-grow
|
|
213
|
-
- On mobile (sm:): search full width, filters wrap to next line
|
|
214
|
-
- Do NOT wrap search/filter toolbars in Card components. They are plain flex rows above content.
|
|
215
|
-
|
|
216
|
-
### Tabs
|
|
217
|
-
- Always use <TabsList variant="line"> for a clean underline style (not the pill/segmented control default)
|
|
218
|
-
- The variant="line" prop removes the bg-muted pill container and uses an underline indicator instead
|
|
219
318
|
|
|
220
319
|
NEVER include marketing sections (hero, pricing, testimonials) on app pages.
|
|
221
320
|
`;
|
|
222
321
|
var DESIGN_QUALITY_AUTH = `
|
|
223
322
|
## DESIGN QUALITY \u2014 AUTH PAGES
|
|
224
323
|
|
|
225
|
-
###
|
|
226
|
-
|
|
227
|
-
|
|
324
|
+
### Reference Pattern (COPY this exact pattern)
|
|
325
|
+
|
|
326
|
+
AUTH CARD:
|
|
327
|
+
\`\`\`
|
|
328
|
+
<div className="w-full max-w-md">
|
|
329
|
+
<Card>
|
|
330
|
+
<CardHeader className="space-y-1">
|
|
331
|
+
<CardTitle className="font-bold text-center">Welcome back</CardTitle>
|
|
332
|
+
<p className="text-sm text-muted-foreground text-center">Enter your credentials</p>
|
|
333
|
+
</CardHeader>
|
|
334
|
+
<CardContent>
|
|
335
|
+
<form className="space-y-4">
|
|
336
|
+
<div className="space-y-2">
|
|
337
|
+
<Label htmlFor="email">Email</Label>
|
|
338
|
+
<Input id="email" type="email" placeholder="Enter your email" />
|
|
339
|
+
</div>
|
|
340
|
+
<div className="space-y-2">
|
|
341
|
+
<Label htmlFor="password">Password</Label>
|
|
342
|
+
<Input id="password" type="password" placeholder="Enter your password" />
|
|
343
|
+
</div>
|
|
344
|
+
<Button type="submit" className="w-full">Sign in</Button>
|
|
345
|
+
</form>
|
|
346
|
+
</CardContent>
|
|
347
|
+
<CardFooter className="text-center">
|
|
348
|
+
<p className="text-sm text-muted-foreground">
|
|
349
|
+
Don't have an account?{' '}
|
|
350
|
+
<Link href="/register" className="text-sm text-muted-foreground underline underline-offset-4 hover:text-foreground transition-colors">Sign up</Link>
|
|
351
|
+
</p>
|
|
352
|
+
</CardFooter>
|
|
353
|
+
</Card>
|
|
354
|
+
</div>
|
|
355
|
+
\`\`\`
|
|
356
|
+
|
|
357
|
+
### Rules
|
|
358
|
+
- The auth layout ALREADY provides centering (flex items-center justify-center min-h-svh). Do NOT add your own centering wrapper.
|
|
228
359
|
- Card width: w-full max-w-md
|
|
229
|
-
- No navigation, no section containers, no sidebar
|
|
230
|
-
- Single focused form with clear CTA
|
|
231
|
-
- Card \u2192 CardHeader (title + description) \u2192 CardContent (form with space-y-4) \u2192 CardFooter (link to other auth page)
|
|
232
|
-
|
|
233
|
-
### Form Spacing
|
|
234
360
|
- Form fields inside CardContent: space-y-4 between field groups
|
|
235
|
-
- Ensure visible gap between the last input field and the submit button (use space-y-4 or space-y-6)
|
|
236
361
|
- Each field group (Label + Input): space-y-2
|
|
237
|
-
|
|
238
|
-
NEVER include navigation bars, sidebars, or multi-section layouts on auth pages.
|
|
362
|
+
- No navigation bars, sidebars, or multi-section layouts on auth pages.
|
|
239
363
|
`;
|
|
240
364
|
var DESIGN_QUALITY_CRITICAL = `
|
|
241
365
|
## CRITICAL CODE RULES (violations will be auto-corrected)
|
|
@@ -267,7 +391,17 @@ function inferPageTypeFromRoute(route) {
|
|
|
267
391
|
"forgot-password",
|
|
268
392
|
"reset-password"
|
|
269
393
|
]);
|
|
270
|
-
const marketingSlugs = /* @__PURE__ */ new Set([
|
|
394
|
+
const marketingSlugs = /* @__PURE__ */ new Set([
|
|
395
|
+
"pricing",
|
|
396
|
+
"features",
|
|
397
|
+
"about",
|
|
398
|
+
"blog",
|
|
399
|
+
"contact",
|
|
400
|
+
"terms",
|
|
401
|
+
"privacy",
|
|
402
|
+
"landing",
|
|
403
|
+
"home"
|
|
404
|
+
]);
|
|
271
405
|
if (authSlugs.has(slug)) return "auth";
|
|
272
406
|
if (marketingSlugs.has(slug) || slug === "") return "marketing";
|
|
273
407
|
return "app";
|
|
@@ -356,9 +490,7 @@ MULTI-SELECT / TAG INPUT:
|
|
|
356
490
|
var RULES_DATA_DISPLAY = `
|
|
357
491
|
DATA DISPLAY RULES:
|
|
358
492
|
|
|
359
|
-
STAT / METRIC CARDS:
|
|
360
|
-
- Pattern: Card > CardHeader(flex flex-row items-center justify-between space-y-0 pb-2) > CardTitle(text-sm font-medium) + Icon(size-4 text-muted-foreground) ; CardContent > metric(text-2xl font-bold) + change(text-xs text-muted-foreground).
|
|
361
|
-
- Grid: grid gap-4 md:grid-cols-2 lg:grid-cols-4.
|
|
493
|
+
STAT / METRIC CARDS: See the Stats Grid reference pattern in DESIGN QUALITY \u2014 APP PAGES. Follow that exact pattern.
|
|
362
494
|
- Trend up: text-emerald-600 (light) / text-emerald-400 (dark) \u2014 exception to semantic-only rule for trend indicators.
|
|
363
495
|
- Trend down: text-destructive.
|
|
364
496
|
- Trend icon: ArrowUp / ArrowDown className="size-3 inline mr-1".
|
|
@@ -379,12 +511,7 @@ PAGINATION:
|
|
|
379
511
|
- Placement: below the list/table, centered. <div className="flex justify-center mt-4">
|
|
380
512
|
- For short lists (<20 items): no pagination. For feeds: "Load more" button (variant="outline" className="w-full").
|
|
381
513
|
|
|
382
|
-
EMPTY STATES:
|
|
383
|
-
- Pattern: <div className="flex flex-col items-center justify-center py-12 text-center">
|
|
384
|
-
- Icon: size-12 text-muted-foreground mb-4 (larger than normal icons \u2014 exception).
|
|
385
|
-
- Title: <h3 className="text-lg font-semibold">No projects yet</h3>
|
|
386
|
-
- Description: <p className="text-sm text-muted-foreground mt-1 max-w-sm">Create your first project to get started.</p>
|
|
387
|
-
- CTA: <Button className="mt-4">Create project</Button>
|
|
514
|
+
EMPTY STATES: See the Empty State reference pattern in DESIGN QUALITY \u2014 APP PAGES. Follow that exact pattern.
|
|
388
515
|
- Search empty: "No results for 'query'. Try different keywords." + clear search button.
|
|
389
516
|
- Filtered empty: "No items match your filters." + reset filters button.
|
|
390
517
|
|
|
@@ -421,9 +548,7 @@ TRUNCATION:
|
|
|
421
548
|
- When to truncate: card descriptions (2 lines), table cells (single line), list item subtitles (1-2 lines).
|
|
422
549
|
- Always set title={fullText} for accessibility on truncated text.
|
|
423
550
|
|
|
424
|
-
SEARCH INPUT:
|
|
425
|
-
- Pattern: <div className="relative"><Search className="absolute left-3 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" /><Input placeholder="Search..." className="pl-9" /></div>
|
|
426
|
-
- Placement: top of the list/table it filters, max-w-sm.
|
|
551
|
+
SEARCH INPUT: See the Filter Toolbar reference pattern in DESIGN QUALITY \u2014 APP PAGES. Use the search input + Select layout shown there.
|
|
427
552
|
- Clear button: X icon on right when value is not empty.
|
|
428
553
|
- Debounce: 300ms on keystroke. No search button.
|
|
429
554
|
`;
|
|
@@ -1115,6 +1240,8 @@ async function generateSharedComponentsFromPlan(plan, styleContext, projectRoot,
|
|
|
1115
1240
|
const componentSpecs = plan.sharedComponents.map(
|
|
1116
1241
|
(c) => `- ${c.name}: ${c.description}. Props: ${c.props}. Type: ${c.type}. shadcn deps: ${c.shadcnDeps.join(", ") || "none"}`
|
|
1117
1242
|
).join("\n");
|
|
1243
|
+
const designRules = `${CORE_CONSTRAINTS}
|
|
1244
|
+
${getDesignQualityForType("app")}`;
|
|
1118
1245
|
const prompt = `Generate React components as separate files. For EACH component below, return an add-page request with name and pageCode fields.
|
|
1119
1246
|
|
|
1120
1247
|
Components to generate:
|
|
@@ -1122,6 +1249,8 @@ ${componentSpecs}
|
|
|
1122
1249
|
|
|
1123
1250
|
Style context: ${styleContext || "default"}
|
|
1124
1251
|
|
|
1252
|
+
${designRules}
|
|
1253
|
+
|
|
1125
1254
|
Requirements:
|
|
1126
1255
|
- Each component MUST have \`export default function ComponentName\`
|
|
1127
1256
|
- Use shadcn/ui imports from @/components/ui/*
|
|
@@ -1173,6 +1302,7 @@ Return JSON with { requests: [{ type: "add-page", changes: { name: "ComponentNam
|
|
|
1173
1302
|
export {
|
|
1174
1303
|
DESIGN_THINKING,
|
|
1175
1304
|
CORE_CONSTRAINTS,
|
|
1305
|
+
DESIGN_QUALITY_COMMON,
|
|
1176
1306
|
getDesignQualityForType,
|
|
1177
1307
|
inferPageTypeFromRoute,
|
|
1178
1308
|
DESIGN_QUALITY,
|