Canvas Design System
Main Site Tokens

Lifecycle

Shows how far a workshop has travelled: Designed → Delivered → Synthesized.

When to Use

Use when: Displaying a saved workshop's position across the Plan → Facilitate → Reflect journey — workshop cards, saved lists, record detail headers. Pass the status derived by getWorkshopRecord() or getWorkshopList().
Don't use when: You mean the planner's manual doc-bar status (Draft / Ready / Live / Done) — that's a different concept with a different control. For a single state label use Badge via ws_status().
info The status is derived, never stored. Designed means a plan row exists; delivered means a completed coaching_sessions row or an ended live session; synthesized means a synthesis_sessions row. Never write a lifecycle value to the database, and never let a caller set it by hand — read it from the Workshop Record.

Variants

Compact (default)

For card footers and list rows. Completed steps fill with very-light red; pending steps stay outlined neutral. State is carried by fill and weight only — never a second hue, which is what keeps it inside Red Unification.

<?= ws_lifecycle(['status' => $workshop['lifecycle_status']]) ?>

Full, with a context CTA

Larger, for a record's detail header. The CTA should be the single next action for the current stage — run it, synthesize it, or read the synthesis.

Run in Facilitator
Synthesize this workshop
View synthesis
<?= ws_lifecycle([
    'status'  => 'delivered',
    'variant' => 'full',
    'cta'     => ['label' => 'Synthesize this workshop',
                  'href'  => '/synthesize/app.php?plan_id=' . $planId],
]) ?>

States

StateMeaning and treatment
designedA plan exists. Step 1 complete, steps 2 and 3 pending.
deliveredThe session ran — a completed coaching_sessions row with linked_plan_id, or an ended live session. Steps 1–2 complete.
synthesizedA synthesis_sessions row exists for the plan. All three complete.
Per-stepSteps carry .is-complete and .is-current. Complete steps show a check in the dot; the current step gets the weight emphasis.
Unknown statusFalls back to designed. Since the value is derived, an unexpected one means the derivation is wrong — fix it upstream.
No CTAThe full variant renders fine without one. The compact variant ignores cta entirely.

Real-World Usage

A saved-workshop card on MyWorkshopr. getWorkshopList() returns rows under the workshops key, each carrying lifecycle_status — pass it straight through rather than recomputing.

Q3 Planning Offsite
8 activities · 3h 20m
<?php
$record = getWorkshopList($userId);          // rows under the `workshops` key
foreach ($record['workshops'] as $w): ?>
    <article class="workshop-card">
        <h3><?= htmlspecialchars($w['title']) ?></h3>
        <?= ws_lifecycle(['status' => $w['lifecycle_status']]) ?>
    </article>
<?php endforeach; ?>

The same strip appears on MyWorkshopr, planner/saved.php, and the Synthesize picker — one component so a workshop's stage reads identically wherever it's seen.

Options

OptionTypeDefaultPurpose
statusstring'designed'designed | delivered | synthesized. Always pass a derived value.
variantstring'compact'compact | full. Only full emits a modifier class.
ctaarraynull['label' => …, 'href' => …]. Full variant only.
idstringnullElement ID
classstring''Additional CSS classes
attrsarray[]Extra HTML attributes

Accessibility

ConcernBehavior
ARIAWell handled. The strip carries role="img" with a composed aria-label, so a screen reader announces the state as one phrase instead of reading three disconnected dots and labels.
StructureSteps are an ordered list, so the sequence is conveyed structurally as well as visually.
Colour independenceCompletion is carried by a check mark inside the dot and by font weight, not by fill alone — it survives greyscale and colour-blindness. This is the pattern to copy elsewhere.
KeyboardThe compact variant has nothing focusable, which is right for a status display. In the full variant the CTA is a normal link.
CTA textThe label is the link's accessible name — "Synthesize this workshop" works out of context; "Continue" wouldn't.
ContrastCompleted steps pair --phase-learn-very-light with --phase-learn-dark; pending steps use --gray-300 on --bg-surface. Both tested.

Tokens

TokenUsed for
--phase-learn / --phase-learn-darkCompleted dot and label
--phase-learn-light / --phase-learn-very-lightCompleted dot fill
--gray-200 / --gray-300Pending dots and the connector line
--bg-surfaceStrip background
--text-mutedPending step labels
--radius-fullStep dots
--text-caption / --text-smallLabel type scale across variants
--font-body / --font-normal / --font-medium / --font-semiboldFace, and the weight step that marks completion
--space-1 / --space-1-5 / --space-2 / --space-3 / --space-4Step spacing across variants

CSS Classes

ClassPurpose
.ws-lifecycleRoot container, carrying role="img"
.ws-lifecycle--fullFull variant (compact is the default and emits no modifier)
.ws-lifecycle__stepsThe <ol>
.ws-lifecycle__stepOne step; takes .is-complete and .is-current
.ws-lifecycle__dotStep circle, showing a check when complete
.ws-lifecycle__labelStep label
.ws-lifecycle__ctaContext action link (full variant)

Files

FilePurpose
includes/components/helpers.phpws_lifecycle() helper function
includes/components/lifecycle.phpTemplate — step states and the composed aria-label
includes/components/components.cssStyles (.ws-lifecycle rules)
includes/workshop-record.phpgetWorkshopRecord() and getWorkshopList() — where the status is derived
api/workshop-record.phpThe federated read, if you need the status client-side