Planner Activity Inspector
The Planner's right column when an activity is selected: everything known about that one item, and what you can do to it.
When to Use
Variants
Canonical — fully annotated activity
Seven sections: identity, overview, energy impact, logistics, notes, when it runs, and actions. The left border carries the type accent so the rail ties visually to the selected card.
instructions turns the overview into a two-tab panel — Overview and Instructions. Without them, the overview renders as a plain block.
Type accents
One type drives the whole card: left border, energy bars, net badge tint, logistics bullets, note rule, and button hover. Never hardcode these downstream.
Minimal — identity and actions
Every section is optional. This is what a custom activity or an un-annotated library item looks like.
States
| State | Behavior |
|---|---|
| Section omitted | Passing null or leaving a key out removes that section entirely, dividers included. The last rendered section takes --section--last. |
| Overview without instructions | Renders as a plain block, no tabs. |
| Overview with instructions | Becomes a tab panel. activeTab chooses which is active on first paint; the tabs carry data-tab and data-tab-group for your switching code. |
| Instructions as array vs string | An array renders a numbered list with mono step counters. A string is rendered as raw HTML — you own the markup, and the escaping. |
| Empty body | With no optional sections at all the body takes --body--empty, tightening the layout rather than leaving a gap. |
| Closable | closable defaults to true, rendering the × in the eyebrow row with data-action="close". Your code handles the click and swaps back to the inspector rail. |
| Action fallback | An action without an explicit action key derives one from its label — "Remove from agenda" becomes remove-from-agenda. Set it explicitly if your handler expects a specific value. |
Real-World Usage
The selection swap in the Planner's right column, with the energy figures coming from the scorer and notes from the facilitator's own record.
<?php if ($selected): ?>
<?= ws_planner_activity_inspector([
'type' => $selected['item_type'],
'duration' => $selected['duration'] . ' min',
'groupSize' => $selected['group_size'],
'title' => $selected['title'],
'tags' => $selected['tags'],
'overview' => $selected['overview'],
'instructions' => $selected['instructions'], // array ⇒ numbered list
'energy' => $energyScorer->itemImpact($selected['id']),
'logistics' => [$selected['duration'] . ' min', $selected['group_size'],
$selected['posture'], $selected['materials']],
'notes' => $notes ? [
'body' => $notes['content'], 'author' => $notes['author'],
'date' => $notes['date'], 'canAdd' => true,
] : null,
'context' => ['time' => $startTime . ' → ' . $endTime,
'description' => 'right after ' . $previous['title']],
'actions' => [
['label' => 'Swap', 'icon' => 'swap_horiz', 'action' => 'swap'],
['label' => 'Duplicate', 'icon' => 'content_copy', 'action' => 'duplicate'],
['label' => 'Adjust', 'icon' => 'schedule', 'action' => 'adjust'],
],
'destructive' => ['label' => 'Remove from agenda', 'icon' => 'close', 'action' => 'remove'],
]) ?>
<?php else: ?>
<?= ws_planner_inspector_rail($railOptions) ?>
<?php endif; ?>Options
| Option | Type | Purpose |
|---|---|---|
title | string | Required. The activity name, in the display face. |
type | string | exercise (default) | icebreaker | break | custom. Drives every accent in the panel. |
duration / groupSize | string | Composed into the eyebrow: EXERCISE · 60 MIN · 6–12 PPL. Omit either to drop it. |
tags | array | Short strings joined with · below the title |
closable | bool | Show the × control. Default true. |
overview | string | One or two sentences. Deeper description belongs on the library detail page. |
instructions | array|string|null | Array of steps, or an HTML string. Presence switches the overview to tabs. |
activeTab | string | overview (default) | instructions |
energy | array|null | ['net', 'dimensions' => [['label', 'delta', 'fill' => 0..100]]]. The net badge is the headline; dimensions are supporting detail. |
logistics | array | Strings in a two-column mono grid with accent-tinted bullets |
notes | array|null | ['body', 'author', 'date', 'canAdd']. Renders as a blockquote with an accent rule; canAdd surfaces the add affordance. |
context | array|null | ['time', 'description'] — when the item runs, as a dashed mono pill |
actions | array | [['label', 'icon?', 'action?', 'href?']]. Three at most at this width — mono labels wrap badly in narrow columns. |
destructive | array|null | One destructive action, full width below the primary row. Keep removal out of actions — the separate slot exists so it reads as different. |
id / class / attrs | string / string / array | Standard passthrough |
Accessibility
| Concern | Behavior |
|---|---|
| Tabs | The overview/instructions panel emits the full pattern: role="tablist", role="tab" with aria-selected and aria-controls, and role="tabpanel" on each panel — better wired than the standalone Tabs component, which never emits panels. |
| Tab keyboard | Same gap as Tabs: the roles promise arrow-key navigation between tabs, but only Tab and Enter/Space work. Two tabs makes it less painful, but the promise is still unmet. |
| Close control | Labelled aria-label="Close inspector" — it names the region, not just the glyph. |
| Decorative icons | Bullets, dividers, and step counters carry aria-hidden="true". |
| Energy bars | The delta is text next to each label, so the number is announced; the bar is reinforcement. Good. |
| Focus on selection | Yours to handle. Swapping the rail replaces the DOM, so focus drops to <body>. Move focus to the inspector's title when it opens, and back to the timeline card when it closes. |
| Destructive action | Marked by a red-tinted border and the word "Remove". Colour is reinforcement, not the signal — keep the verb in the label. |
| Instructions as HTML | A string is rendered raw. Escape anything user-supplied before passing it. |
Tokens
Like its sibling rail, the inspector resolves the shared scales into a locally-scoped set on the root, then references those internally — which is why one type can retint the entire panel.
| Token group | Used for |
|---|---|
Type accent (--planner-*) | Left border stripe, energy bar fills, net badge tint, logistics bullets, note rule, and button hover |
| Surface and edge | Panel background and section dividers — the planner "paper" surface |
| Ink scale | Title, overview, labels, and meta text across four weights |
| Display and mono faces | Fraunces title; mono for eyebrows, tags, logistics, and step counters |
| Error colour | The destructive action's border and hover |
See the .ws-planner-activity-inspector rules in components.css for exact declarations, and Token Reference for values.
CSS Classes
| Class | Purpose |
|---|---|
.ws-planner-activity-inspector | Root panel |
.ws-planner-activity-inspector--exercise / --icebreaker / --break / --custom | Type accents |
__eyebrow / __eyebrow-row | Type, duration, group size, and the close control |
__close | × control, data-action="close" |
__title / __tags | Activity identity |
__tabs / __tab / __panel | Overview / Instructions tab set |
__steps / __step | Numbered instruction list |
__instructions-html | Wrapper when instructions are passed as a string |
__net | Net energy badge |
__dims / __dim / __dim-label / __dim-bar / __dim-fill / __dim-val | Per-dimension energy rows |
__logistics / __log-item | Two-column logistics grid |
__note / __note-attr / __add | Facilitator note, its attribution, and the add affordance |
__when | When-it-runs pill |
__actions / __btn / __btn-icon | Primary action row |
__destructive / __btn--danger | Destructive action |
__section / __section--last / __body / __body--empty / __label | Section scaffolding |
Files
| File | Purpose |
|---|---|
includes/components/helpers.php | ws_planner_activity_inspector() helper function |
includes/components/planner-activity-inspector.php | Template — sections, tab wiring, and accent resolution |
includes/components/components.css | Styles (.ws-planner-activity-inspector rules) |
css/planner/components/_sidebar.css | Planner-side rail styling |