@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.
@@ -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 adapting
18
- `app/layout.ts`, not just the page. Set the real brand, replace the
19
- example `Home` nav, and pick a content-width container that fits. The
20
- default `<main class="max-w-[760px]">` is a reading column for prose and
21
- forms, so for a full-bleed app, dashboard, or board, widen the cap or
22
- remove it (keep the theme tokens). A wide layout left in the 760px
23
- reading column overflows into a horizontal scrollbar. **Give the app a
24
- unique design, and redesign means more than recolor.** When it has a UI,
25
- choose its palette, typography, LAYOUT, and chrome from what the app IS.
26
- Recoloring the scaffold and swapping the logo while keeping its skeleton (a
27
- fixed top header with a Home link and a theme toggle, the centered ~760px
28
- reading column, the "Built with webjs" footer) is NOT a unique design.
29
- Decide from scratch whether this app even needs a header or footer, what nav
30
- (if any), and what layout fits (a centered board, a full-bleed dashboard, a
31
- split, a single card). Before finishing, self-audit that nothing still reads
32
- as the scaffold example (no "Built with webjs" footer, no leftover example
33
- nav, no default reading column unless it truly fits). The `api` template has
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. The delivered app must contain only what the
44
- user asked for, never leftover scaffold code.
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
 
@@ -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. **Adapt `app/layout.ts` to the app, not just the page.** Set the real
369
- brand, replace the example `Home` nav with the app's navigation, and
370
- pick a content-width container that fits. The default
371
- `<main class="max-w-[760px]">` is a reading column for prose, forms,
372
- and marketing. Widen it or drop the cap for a full-bleed app,
373
- dashboard, or board, or a wide layout overflows into an unnecessary
374
- horizontal scrollbar. Keep the design tokens and theme setup, those
375
- are infrastructure.
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. Recoloring the scaffold and
379
- swapping the logo while keeping its skeleton (a fixed top header with a
380
- Home link and a theme toggle, the centered ~760px reading column, the
381
- "Built with webjs" footer) is NOT a unique design. Decide from scratch
382
- whether this app even needs a header or footer, what nav (if any), and
383
- what layout fits (a centered board, a full-bleed dashboard, a split, a
384
- single card). The scaffold ships a `webjs-scaffold-placeholder` marker on
385
- its footer, so `webjs check` fails until you remove or replace the
386
- "Built with webjs" branding. Self-audit before finishing: nothing should
387
- read as the scaffold example (no "Built with webjs" footer, no leftover
388
- example nav, no default reading column unless it truly fits). The design
389
- tokens and theme wiring in `app/layout.ts` are infrastructure to keep and
390
- restyle on top of, not the example look to preserve. Style with Tailwind
391
- utilities wherever they reach, and use custom CSS only for what utilities
392
- cannot express (@theme tokens, @keyframes, scrollbar, complex color-mix
393
- or gradients). The `api` template has no UI, so this does not apply there.
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 ships with the **Tailwind CSS browser runtime** + `@theme`
804
- design tokens defined in the root layout. Every colour, font family,
805
- fluid type scale value, and motion duration is declared once in `@theme`
806
- and available everywhere via utility classes (`text-foreground`,
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.