@webjsdev/cli 0.10.38 → 0.10.39
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/bin/webjs.js +116 -3
- package/lib/clear-placeholders.js +98 -0
- package/lib/create.js +156 -131
- package/lib/db-hints.js +34 -0
- package/lib/design-bar.js +67 -0
- package/lib/doctor.js +122 -4
- package/lib/runtime-rewrite.js +4 -3
- package/package.json +1 -1
- package/templates/.agents/rules/workflow.md +33 -15
- package/templates/.claude/hooks/design-review-before-stop.sh +36 -0
- package/templates/.claude/hooks/route-skills.sh +35 -0
- package/templates/.claude/settings.json +14 -0
- package/templates/.claude/skills/webjs-design-review/SKILL.md +84 -0
- package/templates/.cursorrules +33 -15
- package/templates/.github/copilot-instructions.md +33 -15
- package/templates/AGENTS.md +41 -24
- package/templates/CONVENTIONS.md +60 -29
- package/templates/LAYOUT-REFERENCE.md +96 -0
- package/templates/public/tailwind-browser.js +0 -947
package/templates/AGENTS.md
CHANGED
|
@@ -14,34 +14,51 @@ now (`app/page.ts` printing "Hello from {{APP_NAME}}", the example `User`
|
|
|
14
14
|
model in `db/schema.server.ts`, the `theme-toggle` component, the
|
|
15
15
|
example users module in api/saas templates) are **starting-point
|
|
16
16
|
references, not the final product**. Your job is to replace them with
|
|
17
|
-
the app the user actually asked for. That includes
|
|
18
|
-
`app/layout.ts`, not just the page.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
unique design, and redesign means more than recolor.** When it has a
|
|
25
|
-
choose its palette, typography, LAYOUT, and chrome from what the app IS.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
no UI, so this does not apply there. The design tokens and theme wiring are
|
|
35
|
-
infrastructure to keep and restyle on top of. Style with Tailwind utilities
|
|
36
|
-
wherever they reach, and use custom CSS only for what utilities cannot
|
|
37
|
-
express (@theme tokens, @keyframes, scrollbar, complex color-mix or
|
|
38
|
-
gradients). This is ENFORCED:
|
|
17
|
+
the app the user actually asked for. That includes designing
|
|
18
|
+
`app/layout.ts`, not just the page. It ships as a MINIMAL shell (theme,
|
|
19
|
+
design tokens, and Tailwind infra, then `${children}` in a bare padded
|
|
20
|
+
container) with NO header, nav, footer, or reading column, so design the
|
|
21
|
+
app's own chrome from scratch. `LAYOUT-REFERENCE.md` at the project root is
|
|
22
|
+
a complete worked layout (fixed header, brand, nav, theme toggle, reading
|
|
23
|
+
column, footer) to learn the patterns from, then build your own. **Give the
|
|
24
|
+
app a unique design, and redesign means more than recolor.** When it has a
|
|
25
|
+
UI, choose its palette, typography, LAYOUT, and chrome from what the app IS.
|
|
26
|
+
Decide whether it needs a header at all, a nav (or none), a footer, a
|
|
27
|
+
sidebar, a centered reading column, or a full-bleed canvas (a centered
|
|
28
|
+
board, a full-bleed dashboard, a split, a single card). The `api` template
|
|
29
|
+
has no UI, so this does not apply there. The design tokens and theme wiring
|
|
30
|
+
are infrastructure to keep and set your own palette VALUES on. Style with
|
|
31
|
+
Tailwind utilities wherever they reach, and use custom CSS only for what
|
|
32
|
+
utilities cannot express (@theme tokens, @keyframes, scrollbar, complex
|
|
33
|
+
color-mix or gradients). This is ENFORCED:
|
|
39
34
|
the example `app/page.ts` and `app/layout.ts` carry a
|
|
40
35
|
`webjs-scaffold-placeholder` marker comment, and `webjs check` fails
|
|
41
36
|
while any marker remains, so this freshly scaffolded app fails the check
|
|
42
37
|
until you replace the example content (or deliberately keep it) and
|
|
43
|
-
delete the marker line.
|
|
44
|
-
|
|
38
|
+
delete the marker line. To keep the gallery and clear every marker at
|
|
39
|
+
once, run `webjs check --clear-placeholders` (it strips the marker lines
|
|
40
|
+
and keeps the demo code), then delete any demo you do not want. The
|
|
41
|
+
delivered app must contain only what the user asked for, never leftover
|
|
42
|
+
scaffold code.
|
|
43
|
+
|
|
44
|
+
**Render the app and LOOK before you call UI work done (every agent, not
|
|
45
|
+
just one harness).** You write CSS blind, so a layout or design defect
|
|
46
|
+
ships silently: `webjs check` and `webjs typecheck` pass even when a
|
|
47
|
+
component collapses, grid cells are uneven, the layout resizes as it fills,
|
|
48
|
+
or the app just kept the scaffold's colors. Static tools give no failure
|
|
49
|
+
signal for this. The only thing that catches it is rendering the app and
|
|
50
|
+
looking at the pixels. So for ANY page, layout, or component work: run it
|
|
51
|
+
(`webjs dev`), open every route you changed in a real browser (drive it
|
|
52
|
+
with your harness's browser tool or MCP if it has one, otherwise open it
|
|
53
|
+
yourself and screenshot), and PLAY THROUGH every state (empty, filled, win,
|
|
54
|
+
draw, reload, narrow and wide, light and dark). Confirm nothing collapses
|
|
55
|
+
or reflows, that cells stay equal, that the design is the app's OWN, and
|
|
56
|
+
that both themes read. Ship a real-browser test (`webjs test --browser`)
|
|
57
|
+
for the mechanical floor (measure `getBoundingClientRect()` and assert
|
|
58
|
+
cells stay equal across a move). Fix and re-render until it holds, then
|
|
59
|
+
state what you rendered and confirmed. Claude Code additionally ENFORCES
|
|
60
|
+
this via the `webjs-design-review` skill plus a Stop hook, but the
|
|
61
|
+
discipline is harness-agnostic and applies to every agent.
|
|
45
62
|
|
|
46
63
|
**Non-negotiables for every webjs app:**
|
|
47
64
|
|
package/templates/CONVENTIONS.md
CHANGED
|
@@ -365,32 +365,58 @@ When the user asks the agent to build their actual app:
|
|
|
365
365
|
`app/features/` demos and the `app/examples/` app the real app uses,
|
|
366
366
|
delete the rest (route + module + any table), and remove their links
|
|
367
367
|
from `app/page.ts`.
|
|
368
|
-
5. **
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
368
|
+
5. **Design the layout in `app/layout.ts` (it ships MINIMAL on purpose).**
|
|
369
|
+
The root layout wires the theme, design tokens, and Tailwind (keep all of
|
|
370
|
+
that), then drops `${children}` into a bare padded `<main>` with NO chrome.
|
|
371
|
+
There is no header, nav, footer, or reading column to inherit: design the
|
|
372
|
+
app's own from what the app IS. Decide from scratch whether it needs a
|
|
373
|
+
header at all, a nav (or none), a footer, a sidebar, a centered reading
|
|
374
|
+
column, or a full-bleed canvas. `LAYOUT-REFERENCE.md` at the project root is
|
|
375
|
+
a complete worked layout (fixed header, brand, nav, theme toggle, reading
|
|
376
|
+
column, footer) to learn the patterns from, then build your own. Keep the
|
|
377
|
+
design tokens and theme apparatus, those are infrastructure.
|
|
376
378
|
6. **Use a unique design, and redesign means more than recolor (UI apps).**
|
|
377
379
|
Give the app a design of its own (palette, typography, LAYOUT, spacing,
|
|
378
|
-
and chrome) chosen from what the app IS.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
380
|
+
and chrome) chosen from what the app IS. The layout ships MINIMAL (see item
|
|
381
|
+
5), so there is no scaffold skeleton to inherit: build the chrome the app
|
|
382
|
+
actually needs. Two things are gated by a `webjs-scaffold-placeholder`
|
|
383
|
+
marker, so `webjs check` fails until each is addressed: the minimal shell
|
|
384
|
+
carries a "design your layout from scratch" marker (delete it once you have
|
|
385
|
+
built a real layout), and the palette block carries its own marker (the
|
|
386
|
+
starter orange looks finished on purpose). The design token NAMES and theme
|
|
387
|
+
wiring (`--background`, `--primary`, `--card`, ... in `app/layout.ts`) are
|
|
388
|
+
infrastructure to keep, but their COLOR VALUES are yours: set a distinctive
|
|
389
|
+
palette that fits the app, in both the light and dark blocks. Keeping the
|
|
390
|
+
scaffold's token colors (or a light warm recolor of them) is NOT owning the
|
|
391
|
+
palette. To keep the starter palette deliberately, run
|
|
392
|
+
`webjs check --clear-placeholders`. Style with Tailwind utilities wherever
|
|
393
|
+
they reach, and use custom CSS only for what utilities cannot express (@theme
|
|
394
|
+
tokens, @keyframes, scrollbar, complex color-mix or gradients). The `api`
|
|
395
|
+
template has no UI, so this does not apply there.
|
|
396
|
+
**Size the component HOST, not just an inner wrapper.** A component's host
|
|
397
|
+
custom element is the box its parent lays out. Hosts default to
|
|
398
|
+
`display: block`, but a host that is a flex/grid item in a centering parent
|
|
399
|
+
(`flex justify-center`, `grid place-items-center`) is still sized to its
|
|
400
|
+
content unless it carries width itself. Put `w-full max-w-[...]` on the host,
|
|
401
|
+
not only on an inner `<div>` (an inner `w-full` resolves against a collapsed
|
|
402
|
+
host and the whole component renders tiny). If a board or card renders small
|
|
403
|
+
despite `w-full max-w-[400px]` on its inner grid, move that sizing to the host.
|
|
404
|
+
**Definition of done (design gate):** a UI app is NOT finished until you
|
|
405
|
+
have (a) given it a design of its own (layout AND palette) and removed the
|
|
406
|
+
scaffold shell, (b) run it and PLAYED THROUGH every state in a browser
|
|
407
|
+
(fill the board, win, draw, reload), confirming nothing resizes or shifts as
|
|
408
|
+
it fills (even, stable squares) and it does not resemble the scaffold, and
|
|
409
|
+
(c) confirmed it still reads AND looks right with JavaScript OFF (SSR +
|
|
410
|
+
progressive enhancement): content shows, links navigate, forms submit, and
|
|
411
|
+
the CSS is fully applied (the app links a static compiled `public/tailwind.css`,
|
|
412
|
+
so utilities resolve with no JS). A
|
|
413
|
+
glance at the empty first paint is not enough; the layout bugs show up
|
|
414
|
+
mid-interaction.
|
|
415
|
+
`webjs doctor` emits an advisory when `app/layout` still reproduces scaffold
|
|
416
|
+
design (the exact 760px reading column, the "Built with webjs" attribution, or
|
|
417
|
+
the unmodified starter palette values); the kept theme apparatus (theme-toggle,
|
|
418
|
+
`--header-h`) is infrastructure and does NOT trip it. Treat the advisory as a
|
|
419
|
+
to-do, not noise.
|
|
394
420
|
7. **Keep:** the Drizzle setup, the test config, the agent config files
|
|
395
421
|
(`AGENTS.md`, `CONVENTIONS.md`, `CLAUDE.md`, `.cursorrules`, etc.),
|
|
396
422
|
`db/connection.server.ts` + `db/columns.server.ts`, the directory
|
|
@@ -406,7 +432,9 @@ freshly scaffolded app fails `webjs check` until you address each
|
|
|
406
432
|
placeholder. The marker is acknowledge-and-remove: replace the example
|
|
407
433
|
content, or deliberately keep it, and in either case delete the marker
|
|
408
434
|
line. So the delivered app contains only what the user asked for, never
|
|
409
|
-
leftover scaffold code.
|
|
435
|
+
leftover scaffold code. To keep the gallery and clear every marker in one
|
|
436
|
+
step (instead of one edit per file), run `webjs check --clear-placeholders`,
|
|
437
|
+
then delete whichever demo routes/modules you do not want.
|
|
410
438
|
|
|
411
439
|
The scaffold exists so the agent doesn't reinvent the directory layout,
|
|
412
440
|
the Drizzle wiring, the test runner config, or the convention files. It
|
|
@@ -800,10 +828,13 @@ Both hydrate without flash on the client.
|
|
|
800
828
|
|
|
801
829
|
<!-- OVERRIDE -->
|
|
802
830
|
|
|
803
|
-
The scaffold
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
831
|
+
The scaffold compiles a **static Tailwind stylesheet** (`css:build` builds
|
|
832
|
+
`public/input.css` into the `public/tailwind.css` the layout links, so the
|
|
833
|
+
app is styled with JavaScript off) + `@theme` design tokens. The token
|
|
834
|
+
VALUES live on `:root` in the root layout (plain CSS, JS-off safe); the
|
|
835
|
+
`@theme` maps live in `public/input.css`. Every colour, font family,
|
|
836
|
+
fluid type scale value, and motion duration is declared once and
|
|
837
|
+
available everywhere via utility classes (`text-foreground`,
|
|
807
838
|
`bg-card`, `font-serif`, `duration-fast`, `text-display`).
|
|
808
839
|
|
|
809
840
|
**One theme, canonical tokens.** The app has a SINGLE theme, defined
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Layout reference
|
|
2
|
+
|
|
3
|
+
`app/layout.ts` ships as a **minimal shell**: it wires the theme, design tokens,
|
|
4
|
+
and the linked static Tailwind stylesheet, then renders `${children}` in a bare full-height
|
|
5
|
+
container with no chrome. That is on purpose. A delivered app should design its
|
|
6
|
+
own layout from what the app IS, not inherit a generic header and footer.
|
|
7
|
+
|
|
8
|
+
This file is the **reference** for how to build a real layout: read it to learn
|
|
9
|
+
the patterns (a fixed header, a brand mark, a nav, a theme toggle, a reading
|
|
10
|
+
column, a footer), then write the layout your app actually needs in
|
|
11
|
+
`app/layout.ts`. Decide from scratch: does a tic-tac-toe game want a header at
|
|
12
|
+
all? Does a dashboard want a sidebar instead? Does a landing page want a
|
|
13
|
+
full-bleed hero? Keep only what fits.
|
|
14
|
+
|
|
15
|
+
> **This is ONE example, not a template to reproduce.** Reproducing this exact
|
|
16
|
+
> header (a slim bar with a mark on the left and a theme toggle on the right)
|
|
17
|
+
> just recreates the old scaffold look under a new name. It is here to show the
|
|
18
|
+
> mechanics (how a header, nav, theme toggle, or footer are wired), not the
|
|
19
|
+
> design. Design a layout that fits what THIS app is: a game might be a
|
|
20
|
+
> full-bleed centered stage with no header; a tool might have a compact command
|
|
21
|
+
> bar; a reader might have a wide sidebar. Take the mechanics, invent the form.
|
|
22
|
+
|
|
23
|
+
You do not import from this file. Copy the mechanics you want into
|
|
24
|
+
`app/layout.ts`'s returned template, inside the `<main>` (or replacing it), and
|
|
25
|
+
restyle them into your own design.
|
|
26
|
+
|
|
27
|
+
## A complete worked layout
|
|
28
|
+
|
|
29
|
+
This is the chrome the scaffold used to ship inline. It goes in the body of
|
|
30
|
+
`RootLayout`, after the `<script>`/`<style>` infrastructure blocks. `navLink` is a
|
|
31
|
+
small SSR helper you would declare above `RootLayout`.
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// Declare above RootLayout: a nav-link helper (SSR-time, no client runtime).
|
|
35
|
+
const navLink = (href: string, label: string) => html`
|
|
36
|
+
<a href=${href} class="text-muted-foreground no-underline font-medium text-[13px] leading-none tracking-[0.005em] transition-colors duration-fast hover:text-foreground">${label}</a>
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
// Inside RootLayout's returned html``, in place of the minimal <main>:
|
|
40
|
+
|
|
41
|
+
// A fixed header (NOT sticky: a sticky header flickers on iOS WebKit during a
|
|
42
|
+
// client-router nav). --header-h reserves its height for the content below; the
|
|
43
|
+
// header-measure script already in app/layout.ts sets --header-h to the real
|
|
44
|
+
// height the moment a <header> exists.
|
|
45
|
+
<header class="fixed inset-x-0 top-0 z-20 flex items-center gap-6 px-4 sm:px-6 py-3 border-b border-border bg-[color-mix(in_oklch,var(--background)_75%,transparent)] backdrop-blur-[18px]">
|
|
46
|
+
<a href="/" class="mr-auto inline-flex items-center gap-2 no-underline text-foreground font-semibold text-[15px] leading-none tracking-tight">
|
|
47
|
+
<!-- Your brand or logo mark goes here. A glyph, a wordmark, the real product name. -->
|
|
48
|
+
<span>{{APP_NAME}}</span>
|
|
49
|
+
</a>
|
|
50
|
+
<nav class="flex gap-4 items-center">
|
|
51
|
+
<!-- Your app's real navigation (or drop the nav entirely for a single-page app). -->
|
|
52
|
+
${navLink('/', 'Home')}
|
|
53
|
+
<theme-toggle></theme-toggle>
|
|
54
|
+
</nav>
|
|
55
|
+
</header>
|
|
56
|
+
|
|
57
|
+
// A content shell. The max-w-[760px] cap is a comfortable READING width, right
|
|
58
|
+
// for prose, forms, and marketing. For a full-bleed app, dashboard, or board,
|
|
59
|
+
// widen the cap (for example max-w-[1400px]) or drop the cap and mx-auto for an
|
|
60
|
+
// edge-to-edge layout. A wide layout left in the 760px column overflows into a
|
|
61
|
+
// horizontal scrollbar.
|
|
62
|
+
<div class="flex flex-col min-h-[calc(100dvh-var(--header-h))]">
|
|
63
|
+
<main class="flex-1 w-full max-w-[760px] mx-auto px-4 sm:px-6 pt-[72px] pb-12">
|
|
64
|
+
${children}
|
|
65
|
+
</main>
|
|
66
|
+
<!-- Your footer. Do NOT ship a "Built with webjs" footer: write your app's own. -->
|
|
67
|
+
<footer class="border-t border-border">
|
|
68
|
+
<div class="max-w-[760px] mx-auto px-4 sm:px-6 py-6 flex items-center justify-center">
|
|
69
|
+
<span class="text-sm text-muted-foreground">Your footer</span>
|
|
70
|
+
</div>
|
|
71
|
+
</footer>
|
|
72
|
+
</div>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## The `theme-toggle` element
|
|
76
|
+
|
|
77
|
+
The scaffold ships `components/theme-toggle.ts` (already imported by
|
|
78
|
+
`app/layout.ts` as a side effect, so the element is registered). Place
|
|
79
|
+
`<theme-toggle></theme-toggle>` wherever you want the light/dark switch, or delete
|
|
80
|
+
the import and the theme apparatus in `app/layout.ts` for a single-theme app.
|
|
81
|
+
|
|
82
|
+
## What stays in `app/layout.ts` no matter what
|
|
83
|
+
|
|
84
|
+
The infrastructure above the `<main>` is not chrome and should stay:
|
|
85
|
+
|
|
86
|
+
- the theme-detection `<script>` (light/dark apparatus) and the header-measure
|
|
87
|
+
script,
|
|
88
|
+
- the `<link rel="stylesheet" href="/public/tailwind.css">` (the STATIC stylesheet
|
|
89
|
+
compiled from `public/input.css` by `css:build`, so the app is styled with JS
|
|
90
|
+
off),
|
|
91
|
+
- the `<style>` block of design-token VALUES (`:root` / dark / light), which
|
|
92
|
+
carries its own `webjs-scaffold-placeholder` marker, so own the colors. The
|
|
93
|
+
Tailwind `@theme` maps that turn those tokens into utilities live in
|
|
94
|
+
`public/input.css`.
|
|
95
|
+
|
|
96
|
+
Design the chrome; keep the plumbing.
|