Contributing
Develop Atlas and its documentation side by side, and add a component with the docs it needs.
Atlas and this site are separate repositories —
webreact/atlas and
webreact/atlas-docs — but they are meant to be worked on together. Edit a
component, and the page documenting it should reload.
Working on the package and the docs together
Clone atlas next to the docs app and symlink it in:
git clone [email protected]:webreact/atlas.git packages/atlas composer use-local
use-local registers a path repository and re-resolves the package, so
vendor/webreact/atlas becomes a symlink to your checkout. The app still
imports vendor/webreact/atlas/dist/*; the atlas() Vite plugin in
vite.config.js sees that the package's source files are present and points
those imports at resources/css and resources/js instead, so editing a
component reloads the page you are looking at. The CSP build
(dist/atlas.csp.js) has no single source file and is not redirected.
use-local also publishes the package's development rules
(atlas:rules --dev) for Claude Code, Cursor and Copilot, scoped to
packages/atlas/**. An assistant loads them only when it works on the
package, next to the consumer rules it always has. Edit the package in
packages/atlas, never through vendor/webreact/atlas — the symlink carries
each change over. use-remote removes the development rules again.
Switch back when you are done:
composer use-remote
Running the docs locally
lando start lando vite
The site is at https://atlas-docs.lndo.site. Rebuild the derived files —
search index, markdown twins, llms.txt, sitemap — whenever content changes:
lando docs
That command also renders every documented example, so it is the fastest way to find out whether a change broke one.
Adding a component to the documentation
Documenting a component means adding a directory. There is no route to
register and no navigation array to update — the registry reads
resources/docs and everything follows from what it finds.
resources/docs/components/toggle/
├── meta.php ← title, description, group, keywords, props tables
├── page.blade.php ← the prose, and where each example sits
└── examples/
├── 01-basic.blade.php
└── 02-disabled.blade.php
meta.php returns an array. tags is keyed by the Blade tag a consumer
writes, so compound components document each tag separately:
return [
'title' => 'Toggle',
'description' => 'A switch for a single on/off setting.',
'group' => 'Forms',
'keywords' => ['switch', 'boolean'],
'related' => ['checkbox'],
'tags' => [
'atlas::toggle' => [
'props' => [
['name', 'string', '', 'Name submitted with the form.'],
['checked', 'bool', 'false', 'Whether the switch starts on.'],
],
],
],
];
An example file is exactly the markup a consumer would write, with a comment carrying its title and description:
{{-- title: Basic usage
description: A switch with a label. --}}
<x-atlas::toggle name="notifications" label="Email notifications" />
That one file is rendered live on the component page, rendered again on its own
route at /components/toggle/basic, shown as the code sample, and indexed for
search. Because there is only ever one copy, a snippet cannot drift from the
component it claims to produce.
Three optional metadata keys help with awkward demos.
layout decides how the preview canvas arranges an example's top-level nodes:
inline(the default) is a wrapping row — right for buttons, badges and pills.stackis a column with a gap — for comparing siblings that carry no margins of their own. Atlas headings have none, so six of them in a row would sit shoulder to shoulder.blockis normal document flow — for a composition whose own spacing is part of what the example demonstrates, and for anything full-width.
canvas: 420px sets the preview's minimum height, and iframe: true renders
the preview in its own document — reach for it when a component fights a shared
page, not by default. A fieldset is the usual case: it is a column flex
container, and the shared inline canvas is a row, so it collapses unless it gets
its own document.
Components sort alphabetically inside their group. An order key in meta.php
overrides that — negative values lead — and only affects position within the
group, since group order is declared in ComponentRegistry.
page.blade.php receives $page and places the examples:
<x-docs.example :example="$page->example('basic')" />
<x-docs.heading :level="2" id="disabled">Disabled</x-docs.heading>
<p>Say when a reader should use this, not what the preview already shows.</p>
<x-docs.example :example="$page->example('disabled')" />
House rules for docs content
- English, British spelling. Sentence case for titles.
- Verify props against the component source before writing them down. If a
match(true)block overrides a prop, say so — that behaviour is exactly what a reader cannot guess. - Images take a string
src. Theattachment-idpath calls WordPress and cannot render here. - Component icons are
atlas-*, from the package; content icons are Font Awesome Free (fas-,far-,fab-). An unknown name throws. See Icons. - Prose guides are Markdown; a guide that renders live components is Blade.
Releasing
The documentation follows the package's stable branch, and the version it was
built against is printed in the footer. Tag atlas when a change is ready to
be depended on, and redeploy the docs so the two stay in step.
Quality gates
lando pint # formatting lando stan # static analysis lando pest # tests, including a render check for every component lando docs # renders every documented example
CI runs all four. The render checks exist because Atlas is developed against Radicle, where WordPress is present: a component that only breaks outside WordPress should fail a build rather than the published site.