Phase Toolbar
The dock a phase always wears. ws_app_dock() is the shape; this is the contents: which slots each phase shows, in which order, with which glyph and name.
When to Use
ws_app_dock() directly. Prove has no toolbar at all: its save, share and export act on the document, so they live in the app bar's shared cluster.
What the component owns
The shape is a design decision, reviewable in one file. The wiring is app code the design system has no business knowing. The slot key is the contract between them, so renaming one is a breaking change to every call site of that phase.
| Design system | The app |
|---|---|
| Which slots the phase shows, and in what order | The id a handler binds to |
| Each slot's icon and name | The href a step navigates to |
| The landmark label | The data-action its JS dispatches |
| Whether the phase has lead and trail pills | The text those pills read out, and the badge counts |
The four toolbars
Rendered from includes/components/phase-toolbars.php, the same file the apps render from. The pills below carry sample read-outs because their text is the app's to supply; everything else is exactly what ships.
Strategize
Landmark “Strategize steps”.
Slots: sentence, practice, pitch, check.
Plan
Landmark “Agenda tools”.
Slots: history, cleanup, suggest, share, export, template, deck, calendar, reset.
Facilitate
Landmark “Session controls”.
Slots: polls, reactions, note, moment, joincode.
Synthesize
Landmark “Add material”.
Slots: video, audio, transcript, board, photo, document.
Sanctioned deviations
Three, and only three. Anything beyond them is a design change, and the place to make it is the canon.
A screen drops a slot
One visible line at the call site, so the absence is legible: 'slots' => ['deck' => false, 'calendar' => false]. Here Plan gives up its slide deck and its calendar.
A screen appends one only it has
Appended after the canon's, never interleaved, so the canonical order stays recognisable.
The way forward is closed
The trail pill disables on the same condition the screen's primary does, so the toolbar and the rail can never disagree about whether there is a next step. The toolbar never hides the way forward; it shows it closed.
Usage
<?= ws_phase_toolbar('plan', [
'id' => 'plannerDock',
'hidden' => true,
'slots' => [
'history' => ['id' => 'versionHistoryBtn'],
'cleanup' => ['id' => 'cleanupBtn'],
],
]) ?>
A slot the caller does not mention still renders: the phase's toolbar is the same toolbar wherever that phase appears. The caller's map is read by key, not by position, so writing it in a different order changes nothing. The shell that wears the toolbar sets position: relative on itself and pads its scroll region by --app-dock-clearance while it is showing. Full specification: design-system/spec-phase-toolbar.md.
Accessibility
- The landmark label defaults to the phase's own name, so no screen can ship the generic fallback by forgetting to replace it.
- The canon guarantees every slot has a name, which is the accessibility argument for having a canon: a hand-assembled dock can ship a nameless slot, and this one cannot.
- Every slot's name is its
aria-labeland its tooltip, which opens upward because the toolbar sits at the foot of the region. - A slot passed
'active' => trueannounces as pressed. Strategize marks the step you are on that way. - A static pill is a
<span>. Give itrole="status"throughattrswhen its text changes while the reader works, as Synthesize's count does. - A pill the canon leaves wordless and the caller does not label is dropped rather than drawn blank: an empty lozenge reports nothing.