The repository mixes hand-written source with committed build artifacts. Knowing which is which saves you from editing a file that the next build will overwrite.
Directory Tree
The directories a contributor actually touches, annotated.
zardui/
├── apps/
│ ├── web/ # Documentation site (Angular + SSR/prerender)
│ │ ├── src/app/core/ # Shell and documentation layouts
│ │ ├── src/app/domain/ # Doc components, pages and services
│ │ ├── src/app/shared/ # Routes, constants, pipes, services
│ │ ├── src/generated/ # GENERATED — highlighted code (committed)
│ │ ├── public/documentation/ # Markdown sources for code blocks
│ │ ├── public/docs/ # GENERATED — page Markdown (committed)
│ │ ├── public/blocks/ # Block screenshots (light.png / dark.png)
│ │ ├── prerender-routes.txt # GENERATED by update-routes.mjs
│ │ ├── update-routes.mjs # Rewrites prerender-routes.txt
│ │ └── generate-docs-markdown.mjs # HTML -> public/docs/**.md (post-build)
│ └── web-e2e/ # Playwright E2E specs
├── libs/
│ ├── zard/src/lib/shared/components/ # The component library
│ └── blocks/src/lib/ # Composed blocks
├── packages/
│ ├── highlight/ # Shiki generators + code block components
│ ├── cli/ # zard-cli
│ └── mcp/ # zard-mcp server
├── tools/generators/ # Nx plugin @zardui/generators
├── scripts/ # dev, registry, block sync, commit tooling
└── api/og.ts # Edge function for OG imagesA Component Folder
Every component follows the same shape. The generator creates all of it except the extra demos.
libs/zard/src/lib/shared/components/button/
├── button.component.ts # The component itself
├── button.variants.ts # CVA variants + derived types
├── button.component.spec.ts # Jest unit tests
├── index.ts # Barrel export
├── demo/
│ ├── button.ts # Demo registry consumed by the docs page
│ ├── preview.ts # Hero demo shown at the top of the page
│ └── <example>.ts # One file per example
└── doc/
└── api.ts # API reference (ApiSection[])Where Do I Go?
Find your task on the left, open the path on the right.
| I want to… | Edit | Notes |
|---|---|---|
| Add a new component | libs/zard/src/lib/shared/components/<name>/ | Start with npm run generate:component — it also updates the barrel, the registry and the sidebar. |
| Add a variant to an existing component | libs/zard/src/lib/shared/components/<name>/<name>.variants.ts | Add the key to the CVA variants object; the derived type updates itself. |
| Add a demo | libs/zard/src/lib/shared/components/<name>/demo/ | One file per example, then register it in demo/<name>.ts with its codeData import. |
| Change the API reference | libs/zard/src/lib/shared/components/<name>/doc/api.ts | A typed ApiSection[]. It is not Markdown any more. |
| Add a documentation page | apps/web/src/app/domain/pages/<name>/ | Then register the route, add the sidebar item and rerun update-routes.mjs. |
| Add a block | libs/blocks/src/lib/<name>/ | Run npm run sync:blocks afterwards and add the two screenshots under apps/web/public/blocks/<name>/. |
| Add a sidebar item | apps/web/src/app/shared/constants/routes.constant.ts | The same array feeds the sidebar, the mobile menu and the command palette. |
| Add a CLI command | packages/cli/src/commands/ | Commands are registered from packages/cli/src/index.ts. |
| Add an E2E test | apps/web-e2e/src/components/<name>.spec.ts | Use the ComponentDemoPage helper and the checkA11y wrapper. |
Generated Files
These paths are committed to git — the site serves them and the CLI reads them — but they are produced by a command. Change the source, rerun the command, commit the result.
| Committed path | Produced by |
|---|---|
| apps/web/src/generated/** | npm run generate:highlight |
| apps/web/public/docs/components/**.md | npm run generate:md |
| apps/web/public/docs/**.md | npm run generate:md:docs (after the build) |
| apps/web/prerender-routes.txt | node apps/web/update-routes.mjs |
| apps/web/public/r/** | npm run build:registry |
| libs/blocks/src/lib/<name>/block.ts → files[] | npm run sync:blocks |
Never hand-edit a generated file
Editing apps/web/src/generated , apps/web/public/docs , prerender-routes.txt or a block's files[] array looks like it works until the next build silently reverts it. Edit the source and rerun the generator.