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.
  • stack is 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.
  • block is 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. The attachment-id path 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.