Files
cloudrite/.design-sync/NOTES.md
T
ASOwnerYTandClaude Opus 5 3970cf9a00
Docker / build (push) Failing after 1m43s
Add design-sync inputs for claude.ai/design
Import this repo's components into a Claude Design project so the design
agent builds with the real Cloudrite library instead of generic components.

The repo is a Next.js app, not a component library: no dist/, no exports
map, no .d.ts tree, and Tailwind exists only as build directives. So
.design-sync/ carries a small build that manufactures a consumable package
from source (staged to the gitignored .ds-pkg/):

- tsconfig.dts.json  declaration emit, for real <Name>Props contracts
- build-css.mjs      Tailwind v4 -> a static stylesheet via @tailwindcss/postcss
- make-pkg.mjs       stages the package; index.js exports all 292 symbols
                     while index.d.ts exports only the 61 roots, so shadcn's
                     flat compound parts don't each become a preview card.
                     Also generates the per-root parts tables in docs/
- shims/next-link    router-free anchor; the real next/link needs
                     AppRouterContext and drags in the App Router runtime
- fonts/             Space Grotesk + Inter woff2 (SIL OFL). next/font supplies
                     these at runtime in the app, so the bundle has none

previews/ holds 40 authored preview stories, conventions.md is prepended to
the generated README as the design agent's usage guide, and NOTES.md records
the gotchas a future sync would otherwise rediscover.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-05 17:04:10 +12:00

158 lines
9.7 KiB
Markdown

# design-sync notes — Cloudrite
Repo-specific gotchas for future syncs. Read this before re-running.
## What this repo is
Not a component library — a Next.js 16 marketing site (`private: true`, no `dist/`,
no `exports`, no `.d.ts` tree). The DS surface is `components/ui/*` (54 shadcn/ui
primitives, new-york style) plus 7 hand-built Cloudrite page sections.
## The staging package (`.ds-pkg/`)
The converter needs a package with a built entry and a `.d.ts` tree. Three scripts
under `.design-sync/` build one from source; run them **in this order** (this is
`cfg.buildCmd`):
1. `node_modules/.bin/tsc -p .design-sync/tsconfig.dts.json` — declaration emit,
69 `.d.ts` files. Exits 0; all three steps are chained with `&&`, so a real
failure stops the run.
**`../next-env.d.ts` must stay in that config's `include`.** It pulls in Next's
JSX augmentation for styled-jsx; without it the `<style jsx>` blocks in
`hero.tsx` and `footer.tsx` raise TS2322 and the emit exits non-zero. Those are
not repo errors — `pnpm build` and `tsc --noEmit -p tsconfig.json` are both clean.
2. `node .design-sync/build-css.mjs` — compiles Tailwind v4 → `.design-sync/compiled.css`.
3. `node .design-sync/make-pkg.mjs` — writes `.ds-pkg/{package.json,index.js,index.d.ts}`,
copies the stylesheet + fonts in, and regenerates `.design-sync/docs/*.md`.
`index.js` re-exports **every** symbol from source (292 exports → `window.Cloudrite`),
while `index.d.ts` re-exports only the 61 **roots**. That split is deliberate: shadcn
exports compound parts flat (`CardHeader`, not `Card.Header`), and the converter's
subcomponent grouping only recognises TS-namespace compounds — so without the split
all 292 exports would each get their own preview card. The parts are instead
documented per-root in the generated `.design-sync/docs/<Root>.md` parts tables,
which become the `.prompt.md` the design agent reads.
## Known render warns
- `[DTS_STYLE_SYSTEM] filtering @types/react props` — expected. Most shadcn
primitives type their props as `React.ComponentProps<'div'>`, so the CSS-shorthand
filter trips on React's own DOM prop bag. The emitted `<Name>Props` still carry the
real API (variant unions, `asChild`, etc.). Not a defect.
- `inlined npm packages: 1` in the build log is a pnpm artifact, not a real count —
the metafile regex matches `.pnpm` first in pnpm's `node_modules/.pnpm/<pkg>@ver/...`
layout. The bundle really does inline radix, lucide, cva, etc.
## Gotchas that cost a debugging cycle
- **`cfg.tsconfig` must use `/* */` comments only.** The converter strips `//`
comments with a regex that also mangles a `"//"` JSON *key*, leaving unparseable
JSON. The failure is **silent**: `tsconfigPathsPlugin` returns null, esbuild falls
back to autodiscovering the repo's own `tsconfig.json`, and `next/link` resolves to
the real Next runtime — which bundles the App Router and makes every preview die
with `ReferenceError: process is not defined`.
- **`next/link` is shimmed** to a plain anchor (`.design-sync/shims/next-link.tsx`)
via `compilerOptions.paths`. Header, Hero and Footer import it; the real one needs
`AppRouterContext`, which doesn't exist outside a Next app.
- **CSS edits need a full `package-build.mjs`.** `lib/preview-rebuild.mjs` only
recompiles `_preview/*.js`; it does not re-copy the stylesheet, so a CSS fix appears
to do nothing until the full build runs.
- **Never set `html { background }` in the DS stylesheet.** The card harness paints
`body{background:#fff}` in a later inline `<style>`, so a dark `html` under a white
`body` box paints a black band across the bottom of every card. `body` alone is
correct: designs get the brand surface, cards keep the harness's white chrome.
- **Fonts are self-hosted.** `next/font/google` supplies Space Grotesk + Inter at
runtime in the app, so the repo has no font files. Latin + latin-ext woff2 subsets
were downloaded from Google Fonts into `.design-sync/fonts/` (SIL OFL) and are
committed. `app/globals.css` declares `--font-sans: var(--font-sans), …`, which is a
self-reference that is invalid outside Next — `.design-sync/tailwind-entry.css`
re-declares both families with real stacks.
## Preview conventions (apply to every new preview)
- **Wrap every story in a `Surface`** — `<div className="bg-background text-foreground rounded-lg p-6">`.
Cloudrite is dark-only; `ghost`, `link`, `outline` and `border-border` are all
invisible against the harness's white card body.
- **Overlay / menu components need an open state.** Give them a `defaultOpen` story
and set `cfg.overrides.<Name> = {"cardMode":"single","primaryStory":"Open","viewport":"WxH"}`
— see `Select`. A closed trigger shows none of the compound parts.
- **Animated sections need transitions zeroed.** `Hero` fades in on a 300 ms timer
plus a 1 s transition; the capture harness only waits on fonts and images, so an
unmodified render screenshots at ~10 % opacity. See the `still` style in
`previews/Hero.tsx`. `Features` and `Process` use IntersectionObserver instead and
settle on their own.
- Use real Cloudrite copy (Auckland IT services, 021 107 7483, the four service
lines), never `foo`/`bar`.
- Recompile the CSS after authoring previews: Tailwind only emits utilities for
classes it can see, and `@source './previews'` covers the preview files.
## Excluded from the DS, on purpose
- `components/chatwidget.tsx` — Chatwoot script injector. Renders no markup and
fetches `/api/chatwoot` on mount.
- `components/ui/toaster.tsx` — legacy `Toaster`, colliding with `ui/sonner.tsx`'s.
Sonner wins; the site uses neither.
- `ThemeProvider` — in the bundle (wrap-able) but given no card.
## Re-sync risks
- **`.ds-pkg/` and `.design-sync/compiled.css` are gitignored and regenerated.** A
fresh clone must run all three `buildCmd` steps before the converter, or the entry
and stylesheet won't exist.
- **The scaffolding is inert to the app build, but only because of dot-prefixing.**
`tsconfig.json` includes `**/*.ts(x)` from the repo root with only `node_modules`
excluded; TypeScript's glob matcher skips directories beginning with `.`, which is
the sole reason `.design-sync/previews/*.tsx` (they import `'cloudrite'`, which
does not resolve in the app) and `.ds-pkg/types/**` don't enter the app's program.
Verified: `pnpm build` and a cold `tsc --noEmit` both exit 0. If any of this is ever
moved to a non-dotted path, add it to the app tsconfig's `exclude` first.
- **`next build` is not a substitute for the staging package**, but it *does* compile
the Tailwind stylesheet (~136 KB, hash-named under `.next/static/chunks/*.css`).
That is smaller than `.design-sync/compiled.css` (~170 KB) because Tailwind only
emits classes it can see and the app never references the utilities used by
`.design-sync/previews/`. The app build supplies no library entry and no
declarations, which is what `.ds-pkg/` exists to provide.
- **The fonts are a point-in-time copy.** If Google Fonts revs the woff2, nothing here
notices; the committed files keep working. Re-download only deliberately.
- **The parts tables in `.design-sync/docs/` are generated** by `make-pkg.mjs` from the
declaration emit — never hand-edit them; they are overwritten every run. The prop
signature column falls back to `—` for declarations that aren't plain functions.
- **`ROOT_OVERRIDE` in `make-pkg.mjs` is a hand-maintained exception list** (currently
just `toast.tsx → Toast`, whose first export is the provider). A new shadcn component
whose first export isn't the root needs an entry there.
- Only 40 of 61 components have authored previews; the other 21 ship the floor card and
can be authored on any later sync. `.design-sync/previews/` and the grades carry forward.
- Playwright drives the machine's installed Google Chrome via
`DS_CHROMIUM_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"`
(no 200 MB chromium download). Export it before `package-validate.mjs` /
`package-capture.mjs`, or the render check is skipped.
## Findings for the Cloudrite team (not sync bugs)
- **`--accent` is set to the brand green**, byte-identical to `--primary`
(`oklch(0.75 0.18 145)`), in both the `:root` and `.dark` blocks of
`app/globals.css`. shadcn's default is a low-contrast neutral used for hover and
placeholder surfaces, so every `bg-accent` consumer is now vivid green — most
visibly `Skeleton` (loading blocks render as solid green bars), plus the hover
states in `dropdown-menu`, `command`, `menubar`, `navigation-menu`, `calendar`,
`item`, `toggle`, `button` and `dialog`. The previews render this faithfully
rather than papering over it. If it wasn't intentional, giving `--accent` its own
muted value is a one-line change.
- `styles/globals.css` is an unused light-theme duplicate of `app/globals.css`
(v0 scaffolding). Nothing imports it.
## Gotchas found after the first NOTES pass
- **`package-build.mjs` wipes the whole `--out` dir**, `_screenshots/` included. Any
review sheet captured before a full rebuild is gone; re-run `package-capture.mjs`
for anything still awaiting a grade.
- **Overlay content must not be given `className="relative"`.** Radix positions
`DialogContent` with `fixed` plus `translate(-50%,-50%)`; switching it to `relative`
keeps the translate but drops the centring anchor, so the card clips the title.
Size the card via `cfg.overrides.<Name>.viewport` instead.
- Radix autofocuses the first focusable in an open overlay, which screenshots as a
green text selection. `onOpenAutoFocus={(e) => e.preventDefault()}` gives a clean
still.
- `DS_CHROMIUM_PATH` must be exported for `resync.mjs` too — without it the driver's
validate stage fails `[RENDER_SKIPPED]` and skips capture on `prior_failure`.