@deskwork/studio 0.19.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,41 +1,62 @@
1
1
  /**
2
- * Per-row affordance helpers for the dashboard.
2
+ * Per-row affordance rendering for the dashboard.
3
3
  *
4
- * Pipeline-redesign Task 34. Buttons are static HTML — they link to
5
- * the entry's review surface (`/dev/editorial-review/<uuid>`) or
6
- * carry a `data-copy` payload that the existing studio client copies
7
- * to the clipboard. No new backend handlers are wired here; the
8
- * universal-verb skills are the canonical action path.
4
+ * Implements the v0.20 row-affordance redesign (ACCEPTED archive entry
5
+ * `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/`):
9
6
  *
10
- * Per DESKWORK-STATE-MACHINE.md (v5):
11
- * - Verbs are stage-gated, not state-gated. The iterate button shows
12
- * on stages-that-permit-edits (Ideas/Planned/Outlining/Drafting),
13
- * not on Final (locked) or Published (immutable).
14
- * - Revisions (the iteration counter) are bookkeeping. They do not
15
- * surface in routine UI; the operator only sees them via revision
16
- * history / revert flows. The previous "iteration: N" per-row
17
- * display has been removed.
7
+ * - **Mobile** — the row at-rest is clean (slug + title + date). A trailing
8
+ * `⋮` button toggles a menu popover with the FULL stage-aware verb set.
9
+ * Swipe-left on the row reveals a drawer with the TOP-N stage-aware verbs
10
+ * as colored chips (fast power-user path).
11
+ * - **Desktop** — high-frequency verbs (iterate / approve / view / induct
12
+ * as applicable) render as inline outlined chips next to the row. The same
13
+ * `⋮` button + menu hold the secondary verbs (block / cancel / scrapbook).
14
+ *
15
+ * Stage-aware verb vocabulary per DESKWORK-STATE-MACHINE.md (Commandment II
16
+ * — verbs are stage-gated). The block + induct verbs are surfaced uniformly
17
+ * on every linear-pipeline stage (block pauses an in-pipeline entry; induct
18
+ * teleports to an operator-chosen stage in either direction). Both clipboard-
19
+ * copy their `/deskwork:<verb> <slug>` slash command; the receiving agent
20
+ * runs the atomic CLI helper (`deskwork block / cancel / induct`).
21
+ *
22
+ * The row's outer wrapper is `.er-row-shell` (was `.er-calendar-row-wrap`).
23
+ * Inside: a `.er-row-drawer` for the swipe-action chips (positioned right of
24
+ * the foreground; hidden behind it at-rest), the `.er-row-fg` foreground
25
+ * content (translates left on swipe to reveal the drawer), and a
26
+ * `.er-row-menu` popover (absolute-positioned, hidden by default; surfaced
27
+ * when `⋮` is clicked). The client controller `row-actions.ts` wires the
28
+ * gestures + menu state.
18
29
  */
19
30
  import { type RawHtml } from '../html.ts';
20
31
  import type { Entry } from '@deskwork/core/schema/entry';
21
32
  /**
22
- * Build the per-row action strip. Affordances vary by stage:
33
+ * Render the row's affordance chrome drawer + inline chips + ⋮ button.
23
34
  *
24
- * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
25
- * "open →" link, "iterate →" copy-CLI button (always; no state gate),
26
- * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
27
- * - Final: "open →", "approve →" (graduates to Published; assigns a
28
- * version per the operator's scheme), "cancel ⊘". NO iterate
29
- * (Final locks content per the spec).
30
- * - Published: "view →" (read-only review surface). Future enhancement:
31
- * surface a "revise" affordance that inducts back to Drafting.
32
- * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
35
+ * Returned HTML expects to be embedded inside the row's foreground container
36
+ * (`.er-row-fg`). The drawer + menu live as siblings of `.er-row-fg` inside
37
+ * `.er-row-shell`; section.ts owns that outer composition.
33
38
  *
34
- * All non-terminal stages also get a `scrapbook ↗` link (#157).
39
+ * Three pieces:
40
+ * 1. Inline chips — high-frequency verbs as outlined chips (desktop only;
41
+ * CSS hides them on mobile).
42
+ * 2. Overflow `⋮` button — toggles the menu popover. Visible on both
43
+ * mobile and desktop.
35
44
  *
36
- * Each button's behavior is parked behind a `data-copy` attribute so
37
- * the existing studio client (editorial-studio-client.ts) handles
38
- * clipboard wiring without new server handlers.
45
+ * Drawer + menu are rendered separately via `renderRowDrawer` and
46
+ * `renderRowMenu` (also exported) so section.ts can place them in the
47
+ * correct outer layout (drawer is sibling of `.er-row-fg`; menu is sibling
48
+ * of `.er-row-fg`).
39
49
  */
40
50
  export declare function renderRowActions(entry: Entry, defaultSite: string): RawHtml;
51
+ /**
52
+ * Drawer rendered as a sibling of `.er-row-fg`. Absolute-positioned at the
53
+ * row's trailing edge; hidden behind the foreground at-rest. Revealed by
54
+ * the foreground translating left on swipe.
55
+ */
56
+ export declare function renderRowDrawer(entry: Entry, defaultSite: string): RawHtml;
57
+ /**
58
+ * Menu popover rendered as a sibling of `.er-row-fg`. Hidden by default
59
+ * (the controller flips `hidden` + `aria-expanded` on the overflow button).
60
+ */
61
+ export declare function renderRowMenu(entry: Entry, defaultSite: string): RawHtml;
41
62
  //# sourceMappingURL=affordances.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"affordances.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,6BAA6B,CAAC;AAEhE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAkE3E"}
1
+ {"version":3,"file":"affordances.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,6BAA6B,CAAC;AA6QhE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAgB3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAG1E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAGxE"}
@@ -1,125 +1,311 @@
1
1
  /**
2
- * Per-row affordance helpers for the dashboard.
2
+ * Per-row affordance rendering for the dashboard.
3
3
  *
4
- * Pipeline-redesign Task 34. Buttons are static HTML — they link to
5
- * the entry's review surface (`/dev/editorial-review/<uuid>`) or
6
- * carry a `data-copy` payload that the existing studio client copies
7
- * to the clipboard. No new backend handlers are wired here; the
8
- * universal-verb skills are the canonical action path.
4
+ * Implements the v0.20 row-affordance redesign (ACCEPTED archive entry
5
+ * `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/`):
9
6
  *
10
- * Per DESKWORK-STATE-MACHINE.md (v5):
11
- * - Verbs are stage-gated, not state-gated. The iterate button shows
12
- * on stages-that-permit-edits (Ideas/Planned/Outlining/Drafting),
13
- * not on Final (locked) or Published (immutable).
14
- * - Revisions (the iteration counter) are bookkeeping. They do not
15
- * surface in routine UI; the operator only sees them via revision
16
- * history / revert flows. The previous "iteration: N" per-row
17
- * display has been removed.
7
+ * - **Mobile** — the row at-rest is clean (slug + title + date). A trailing
8
+ * `⋮` button toggles a menu popover with the FULL stage-aware verb set.
9
+ * Swipe-left on the row reveals a drawer with the TOP-N stage-aware verbs
10
+ * as colored chips (fast power-user path).
11
+ * - **Desktop** — high-frequency verbs (iterate / approve / view / induct
12
+ * as applicable) render as inline outlined chips next to the row. The same
13
+ * `⋮` button + menu hold the secondary verbs (block / cancel / scrapbook).
14
+ *
15
+ * Stage-aware verb vocabulary per DESKWORK-STATE-MACHINE.md (Commandment II
16
+ * — verbs are stage-gated). The block + induct verbs are surfaced uniformly
17
+ * on every linear-pipeline stage (block pauses an in-pipeline entry; induct
18
+ * teleports to an operator-chosen stage in either direction). Both clipboard-
19
+ * copy their `/deskwork:<verb> <slug>` slash command; the receiving agent
20
+ * runs the atomic CLI helper (`deskwork block / cancel / induct`).
21
+ *
22
+ * The row's outer wrapper is `.er-row-shell` (was `.er-calendar-row-wrap`).
23
+ * Inside: a `.er-row-drawer` for the swipe-action chips (positioned right of
24
+ * the foreground; hidden behind it at-rest), the `.er-row-fg` foreground
25
+ * content (translates left on swipe to reveal the drawer), and a
26
+ * `.er-row-menu` popover (absolute-positioned, hidden by default; surfaced
27
+ * when `⋮` is clicked). The client controller `row-actions.ts` wires the
28
+ * gestures + menu state.
18
29
  */
19
30
  import { html, unsafe } from "../html.js";
20
31
  import { scrapbookViewerUrl } from "../../components/scrapbook-item.js";
21
32
  /**
22
- * Build the per-row action strip. Affordances vary by stage:
23
- *
24
- * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
25
- * "open →" link, "iterate →" copy-CLI button (always; no state gate),
26
- * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
27
- * - Final: "open →", "approve →" (graduates to Published; assigns a
28
- * version per the operator's scheme), "cancel ⊘". NO iterate
29
- * (Final locks content per the spec).
30
- * - Published: "view →" (read-only review surface). Future enhancement:
31
- * surface a "revise" affordance that inducts back to Drafting.
32
- * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
33
- *
34
- * All non-terminal stages also get a `scrapbook ↗` link (#157).
33
+ * Build the stage-aware verb set for an entry. Returns three views — the
34
+ * inline-chip set (desktop high-frequency verbs), the drawer set (mobile
35
+ * swipe top-N), and the menu set (full stage-aware vocabulary).
35
36
  *
36
- * Each button's behavior is parked behind a `data-copy` attribute so
37
- * the existing studio client (editorial-studio-client.ts) handles
38
- * clipboard wiring without new server handlers.
37
+ * Visibility-by-surface is intentional and documented in
38
+ * `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/brief.md`.
39
39
  */
40
- export function renderRowActions(entry, defaultSite) {
41
- const buttons = [];
42
- const stage = entry.currentStage;
40
+ function verbsForStage(stage, entry, defaultSite) {
41
+ const slug = entry.slug;
43
42
  const reviewLink = `/dev/editorial-review/entry/${entry.uuid}`;
44
- // Scrapbook URL uses the project's defaultSite. Multi-site calendars
45
- // would require a per-entry site lookup (out of scope for #157 — the
46
- // primary value is the dashboard ↔ scrapbook entry point existing at
47
- // all, and most projects have a single site). Slug already contains
48
- // any hierarchical path segments.
49
- //
50
- // #205: thread the entry's UUID through `scrapbookViewerUrl` so the
51
- // standalone viewer's server route resolves the listing via
52
- // `scrapbookDirForEntry` for entries whose on-disk path doesn't match
53
- // the slug template (e.g. feature-doc layouts under
54
- // `docs/<version>/<status>/<slug>/`). Falls back to slug-template
55
- // addressing for entries without an id binding.
43
+ // Scrapbook URL uses the project's defaultSite (#157, #205). Slug already
44
+ // contains any hierarchical segments.
56
45
  const scrapLink = scrapbookViewerUrl({
57
46
  site: defaultSite,
58
- path: entry.slug,
47
+ path: slug,
59
48
  entryId: entry.uuid,
60
49
  });
61
- if (isLinearActiveStage(stage)) {
62
- buttons.push(html `<a class="er-btn er-btn-small" href="${reviewLink}"
63
- title="open the review surface for ${entry.slug}">open →</a>`);
64
- // Iterate — stage-gated per DESKWORK-STATE-MACHINE.md Commandment II:
65
- // verbs are stage-gated, never state-gated. Iterate runs on stages
66
- // that permit edits (Ideas / Planned / Outlining / Drafting); Final
67
- // locks content so iterate is hidden there. The previous
68
- // `reviewState === 'iterating'` gate was a Commandment II violation;
69
- // removed in the v0.19 spec-conformance sweep.
70
- if (stagePermitsEdits(stage)) {
71
- buttons.push(html `<button class="er-btn er-btn-small er-btn-primary er-copy-btn" type="button"
72
- data-copy="/deskwork:iterate ${entry.slug}"
73
- title="operator clicked Iterate run the iterate skill in Claude Code">iterate →</button>`);
74
- }
75
- // Approve (#244) unconditional on active-pipeline rows. Mirrors
76
- // the review-surface decision strip (Approve is always visible
77
- // there); the dashboard previously gated this button on
78
- // `reviewState === 'approved'`, which is a transient state most
79
- // rows never carry, leaving the button effectively invisible. The
80
- // operator should be able to advance any active-pipeline entry
81
- // from the dashboard without first opening the review surface.
82
- buttons.push(html `<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
83
- data-copy="/deskwork:approve ${entry.slug}"
84
- title="advance this entry to the next stage">approve →</button>`);
85
- // Cancel (#242) — pull this entry off-pipeline. Same clipboard
86
- // routing as approve / iterate; the skill mutates sidecar + journal.
87
- buttons.push(html `<button class="er-btn er-btn-small er-btn-reject er-copy-btn" type="button"
88
- data-copy="/deskwork:cancel ${entry.slug}"
89
- title="pull this entry off-pipeline (Cancelled). Reversible via /deskwork:induct.">cancel ⊘</button>`);
50
+ const iterate = {
51
+ kind: 'iterate',
52
+ label: 'Iterate',
53
+ glyph: '↻',
54
+ copy: `/deskwork:iterate ${slug}`,
55
+ title: 'append a new revision to this entry',
56
+ };
57
+ const approve = {
58
+ kind: 'approve',
59
+ label: stage === 'Final' ? 'Approve → Published' : 'Approve',
60
+ glyph: '✓',
61
+ // Per DESKWORK-STATE-MACHINE.md Commandment II, approve is universal
62
+ // across every linear-pipeline transition including Final Published.
63
+ // The `/deskwork:approve` skill handles all stage transitions; the
64
+ // separate `/deskwork:publish` skill is an alias for the Final →
65
+ // Published case, not a separate verb. Use approve uniformly.
66
+ copy: `/deskwork:approve ${slug}`,
67
+ title: stage === 'Final'
68
+ ? 'advance this entry to Published (assigns a public version)'
69
+ : 'advance this entry to the next stage',
70
+ };
71
+ const block = {
72
+ kind: 'block',
73
+ label: 'Block (pause)',
74
+ glyph: '‖',
75
+ copy: `/deskwork:block ${slug}`,
76
+ title: 'pause this entry without abandoning it (reversible via /deskwork:induct)',
77
+ };
78
+ const induct = {
79
+ kind: 'induct',
80
+ label: 'Induct… (pick stage)',
81
+ glyph: '⇄',
82
+ copy: `/deskwork:induct ${slug}`,
83
+ title: 'teleport this entry to a chosen stage (forward or backward)',
84
+ };
85
+ const cancel = {
86
+ kind: 'cancel',
87
+ label: 'Cancel',
88
+ glyph: '⊘',
89
+ copy: `/deskwork:cancel ${slug}`,
90
+ title: 'pull this entry off-pipeline (Cancelled; rarely resumed)',
91
+ };
92
+ const view = {
93
+ kind: 'view',
94
+ label: 'View',
95
+ glyph: '→',
96
+ href: reviewLink,
97
+ title: 'read-only review surface for the published entry',
98
+ };
99
+ const scrapbook = {
100
+ kind: 'scrapbook',
101
+ label: 'Open scrapbook',
102
+ glyph: '⊞',
103
+ href: scrapLink,
104
+ title: "open the entry's scrapbook (research notes, drafts, etc.)",
105
+ drawerLabel: 'Scrpbk',
106
+ };
107
+ // Used only on Blocked/Cancelled rows where induct's primary use is
108
+ // bringing the entry back into the pipeline.
109
+ const inductForward = {
110
+ ...induct,
111
+ label: 'Induct… (pick stage)',
112
+ title: 'bring this entry back into the pipeline',
113
+ };
114
+ if (stage === 'Ideas' || stage === 'Planned' || stage === 'Outlining' || stage === 'Drafting') {
115
+ return {
116
+ // Scrapbook stays inline on every stage — it's the entry's research
117
+ // surface, used at the same cadence as the active-stage verb.
118
+ inline: [iterate, approve, scrapbook],
119
+ drawer: [iterate, approve, cancel, scrapbook],
120
+ menu: [iterate, approve, block, induct, cancel, scrapbook],
121
+ };
122
+ }
123
+ if (stage === 'Final') {
124
+ return {
125
+ inline: [approve, scrapbook],
126
+ drawer: [approve, cancel, scrapbook],
127
+ menu: [approve, block, induct, cancel, scrapbook],
128
+ };
129
+ }
130
+ if (stage === 'Blocked' || stage === 'Cancelled') {
131
+ return {
132
+ inline: [inductForward, scrapbook],
133
+ drawer: [inductForward, scrapbook],
134
+ menu: [inductForward, scrapbook],
135
+ };
90
136
  }
91
- else if (stage === 'Published') {
92
- buttons.push(html `<a class="er-btn er-btn-small" href="${reviewLink}"
93
- title="read-only review surface for the published entry">view →</a>`);
137
+ if (stage === 'Published') {
138
+ // Frozen artifact; view + scrapbook only.
139
+ return {
140
+ inline: [view, scrapbook],
141
+ drawer: [view, scrapbook],
142
+ menu: [view, scrapbook],
143
+ };
94
144
  }
95
- else if (stage === 'Blocked' || stage === 'Cancelled') {
96
- buttons.push(html `<button class="er-btn er-btn-small er-copy-btn" type="button"
97
- data-copy="/deskwork:induct ${entry.slug}"
98
- title="bring this entry back into the pipeline">induct →</button>`);
145
+ // Exhaustiveness check — if the Stage union gains a new variant, the
146
+ // assertion will fail at typecheck time and at runtime so we don't
147
+ // silently fall through to an empty verb set.
148
+ const _exhaustive = stage;
149
+ throw new Error(`verbsForStage: unhandled stage "${String(_exhaustive)}"`);
150
+ }
151
+ function renderDrawerChip(verb) {
152
+ const labelText = verb.drawerLabel ?? verb.label.split(' ')[0];
153
+ // Route the data attribute through the html tag so its value is
154
+ // properly attribute-escaped. Slug regex constrains the payload today
155
+ // (no unbalanced quotes possible) but future-verb churn could land a
156
+ // payload with HTML-sensitive characters; the tag handles them.
157
+ if (verb.copy !== undefined) {
158
+ return html `<button type="button"
159
+ class="er-row-action er-row-action-${verb.kind}"
160
+ data-copy="${verb.copy}"
161
+ title="${verb.title}">
162
+ <span class="er-row-action-glyph" aria-hidden="true">${verb.glyph}</span>
163
+ <span class="er-row-action-label">${labelText}</span>
164
+ </button>`;
165
+ }
166
+ return html `<button type="button"
167
+ class="er-row-action er-row-action-${verb.kind}"
168
+ data-href="${verb.href ?? ''}"
169
+ title="${verb.title}">
170
+ <span class="er-row-action-glyph" aria-hidden="true">${verb.glyph}</span>
171
+ <span class="er-row-action-label">${labelText}</span>
172
+ </button>`;
173
+ }
174
+ function renderInlineChip(verb) {
175
+ // Inline chips are the high-frequency desktop affordances. View +
176
+ // scrapbook render as plain links (no clipboard); the rest are
177
+ // clipboard-copy buttons routing slash commands. Scrapbook links
178
+ // also carry `data-action="open-scrapbook"` so the existing client
179
+ // can distinguish them from review-surface links (#157, #205).
180
+ if (verb.href !== undefined) {
181
+ const dataAction = verb.kind === 'scrapbook' ? ' data-action="open-scrapbook"' : '';
182
+ return html `<a class="er-btn-chip er-btn-chip-${verb.kind}"
183
+ href="${verb.href}"${unsafe(dataAction)} title="${verb.title}">${verb.label} ${verb.glyph}</a>`;
99
184
  }
100
- // Scrapbook link follows every stage's primary action.
101
- buttons.push(html `<a class="er-btn er-btn-small er-btn-scrap"
102
- href="${scrapLink}" data-action="open-scrapbook"
103
- title="open the entry's scrapbook (research notes, drafts, etc.)">scrapbook ↗</a>`);
104
- return unsafe(`<span class="er-calendar-action">${buttons.join('')}</span>`);
185
+ return html `<button type="button"
186
+ class="er-btn-chip er-btn-chip-${verb.kind} er-copy-btn"
187
+ data-copy="${verb.copy ?? ''}"
188
+ title="${verb.title}">${verb.label.toLowerCase()} ${verb.glyph}</button>`;
105
189
  }
106
- function isLinearActiveStage(stage) {
107
- return (stage === 'Ideas' ||
108
- stage === 'Planned' ||
109
- stage === 'Outlining' ||
110
- stage === 'Drafting' ||
111
- stage === 'Final');
190
+ function renderMenuItem(verb) {
191
+ // Short command hint matching the mockup's compact form:
192
+ // copy verbs `/deskwork:approve` (verb only, no slug)
193
+ // href verbs `/dev/scrapbook` / `/dev/editorial-review` (path stem,
194
+ // no site / uuid / query string)
195
+ // The clipboard-copy still routes the FULL slash command via data-copy;
196
+ // hrefs still navigate to the full URL via data-href. The hint is just a
197
+ // visual reminder of which command/route is being invoked — appending the
198
+ // slug / full path doubles the cmd cell width and forces the label to
199
+ // wrap on narrow viewports.
200
+ const cmdHint = verb.copy !== undefined
201
+ ? verb.copy.split(' ', 1)[0]
202
+ : (verb.href ?? '').split('/').slice(0, 3).join('/');
203
+ // Route data attributes through the html tag for proper escaping.
204
+ if (verb.href !== undefined) {
205
+ return html `<button type="button"
206
+ class="er-row-menu-item"
207
+ role="menuitem"
208
+ data-href="${verb.href}"
209
+ title="${verb.title}">
210
+ <span class="er-row-menu-glyph er-row-menu-glyph-${verb.kind}" aria-hidden="true">${verb.glyph}</span>
211
+ <span class="er-row-menu-label">${verb.label}</span>
212
+ <span class="er-row-menu-cmd">${cmdHint}</span>
213
+ </button>`;
214
+ }
215
+ return html `<button type="button"
216
+ class="er-row-menu-item"
217
+ role="menuitem"
218
+ data-copy="${verb.copy ?? ''}"
219
+ title="${verb.title}">
220
+ <span class="er-row-menu-glyph er-row-menu-glyph-${verb.kind}" aria-hidden="true">${verb.glyph}</span>
221
+ <span class="er-row-menu-label">${verb.label}</span>
222
+ <span class="er-row-menu-cmd">${cmdHint}</span>
223
+ </button>`;
224
+ }
225
+ /**
226
+ * Group menu items per the mockup's visual rhythm:
227
+ * primary verbs · divider · secondary (block / induct) · divider · off-pipeline
228
+ *
229
+ * For Blocked/Cancelled/Published the menu is short enough to skip dividers.
230
+ */
231
+ function renderMenu(stage, menu) {
232
+ const isShort = stage === 'Blocked' || stage === 'Cancelled' || stage === 'Published';
233
+ if (isShort) {
234
+ return menu.map(renderMenuItem).join('');
235
+ }
236
+ // Active + Final use grouped layout.
237
+ const primary = [];
238
+ const secondary = [];
239
+ const tail = [];
240
+ for (const v of menu) {
241
+ if (v.kind === 'iterate' || v.kind === 'approve')
242
+ primary.push(v);
243
+ else if (v.kind === 'block' || v.kind === 'induct')
244
+ secondary.push(v);
245
+ else
246
+ tail.push(v);
247
+ }
248
+ const divider = '<hr class="er-row-menu-divider" role="separator" />';
249
+ return [
250
+ ...primary.map(renderMenuItem),
251
+ primary.length > 0 && secondary.length > 0 ? divider : '',
252
+ ...secondary.map(renderMenuItem),
253
+ secondary.length > 0 && tail.length > 0 ? divider : '',
254
+ ...tail.map(renderMenuItem),
255
+ ]
256
+ .filter(Boolean)
257
+ .join('');
258
+ }
259
+ /**
260
+ * Render the row's affordance chrome — drawer + inline chips + ⋮ button.
261
+ *
262
+ * Returned HTML expects to be embedded inside the row's foreground container
263
+ * (`.er-row-fg`). The drawer + menu live as siblings of `.er-row-fg` inside
264
+ * `.er-row-shell`; section.ts owns that outer composition.
265
+ *
266
+ * Three pieces:
267
+ * 1. Inline chips — high-frequency verbs as outlined chips (desktop only;
268
+ * CSS hides them on mobile).
269
+ * 2. Overflow `⋮` button — toggles the menu popover. Visible on both
270
+ * mobile and desktop.
271
+ *
272
+ * Drawer + menu are rendered separately via `renderRowDrawer` and
273
+ * `renderRowMenu` (also exported) so section.ts can place them in the
274
+ * correct outer layout (drawer is sibling of `.er-row-fg`; menu is sibling
275
+ * of `.er-row-fg`).
276
+ */
277
+ export function renderRowActions(entry, defaultSite) {
278
+ const { inline } = verbsForStage(entry.currentStage, entry, defaultSite);
279
+ const chips = inline.map(renderInlineChip).join('');
280
+ const overflow = html `<button type="button"
281
+ class="er-row-overflow"
282
+ data-row-overflow
283
+ aria-haspopup="menu"
284
+ aria-expanded="false"
285
+ aria-label="More actions">⋮</button>`;
286
+ // Keep `.er-calendar-action` as the wrapper class so the existing
287
+ // mobile grid-template-areas (`action` area at row 3 of the row
288
+ // grid) and desktop layout rules continue to position the chrome.
289
+ // The `.er-row-affordances` class is added alongside as a v0.20
290
+ // marker for any future rules that need to target the new chrome
291
+ // specifically.
292
+ return unsafe(`<span class="er-calendar-action er-row-affordances">${chips}${overflow}</span>`);
293
+ }
294
+ /**
295
+ * Drawer rendered as a sibling of `.er-row-fg`. Absolute-positioned at the
296
+ * row's trailing edge; hidden behind the foreground at-rest. Revealed by
297
+ * the foreground translating left on swipe.
298
+ */
299
+ export function renderRowDrawer(entry, defaultSite) {
300
+ const { drawer } = verbsForStage(entry.currentStage, entry, defaultSite);
301
+ return unsafe(html `<div class="er-row-drawer" aria-hidden="true">${unsafe(drawer.map(renderDrawerChip).join(''))}</div>`);
112
302
  }
113
303
  /**
114
- * Stages that permit content edits (and therefore iterate). Final
115
- * locks content per DESKWORK-STATE-MACHINE.md iterate refuses there;
116
- * the operator must induct backward to a stage that permits edits if
117
- * they want to revise a Final entry.
304
+ * Menu popover rendered as a sibling of `.er-row-fg`. Hidden by default
305
+ * (the controller flips `hidden` + `aria-expanded` on the overflow button).
118
306
  */
119
- function stagePermitsEdits(stage) {
120
- return (stage === 'Ideas' ||
121
- stage === 'Planned' ||
122
- stage === 'Outlining' ||
123
- stage === 'Drafting');
307
+ export function renderRowMenu(entry, defaultSite) {
308
+ const { menu } = verbsForStage(entry.currentStage, entry, defaultSite);
309
+ return unsafe(html `<div class="er-row-menu" role="menu" hidden>${unsafe(renderMenu(entry.currentStage, menu))}</div>`);
124
310
  }
125
311
  //# sourceMappingURL=affordances.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,WAAmB;IAChE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;IACjC,MAAM,UAAU,GAAG,+BAA+B,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,qEAAqE;IACrE,qEAAqE;IACrE,qEAAqE;IACrE,oEAAoE;IACpE,kCAAkC;IAClC,EAAE;IACF,oEAAoE;IACpE,4DAA4D;IAC5D,sEAAsE;IACtE,oDAAoD;IACpD,kEAAkE;IAClE,gDAAgD;IAChD,MAAM,SAAS,GAAG,kBAAkB,CAAC;QACnC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,IAAI;KACpB,CAAC,CAAC;IAEH,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,wCAAwC,UAAU;2CAC5B,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC;QACjE,sEAAsE;QACtE,mEAAmE;QACnE,oEAAoE;QACpE,yDAAyD;QACzD,qEAAqE;QACrE,+CAA+C;QAC/C,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;uCACgB,KAAK,CAAC,IAAI;mGACkD,CAAC,CAAC;QACjG,CAAC;QACD,kEAAkE;QAClE,+DAA+D;QAC/D,wDAAwD;QACxD,gEAAgE;QAChE,kEAAkE;QAClE,+DAA+D;QAC/D,+DAA+D;QAC/D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;qCACgB,KAAK,CAAC,IAAI;sEACuB,CAAC,CAAC;QACpE,+DAA+D;QAC/D,qEAAqE;QACrE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;oCACe,KAAK,CAAC,IAAI;2GAC6D,CAAC,CAAC;IAC3G,CAAC;SAAM,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,wCAAwC,UAAU;0EACG,CAAC,CAAC;IAC1E,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;oCACe,KAAK,CAAC,IAAI;wEAC0B,CAAC,CAAC;IACxE,CAAC;IAED,uDAAuD;IACvD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;YACP,SAAS;sFACiE,CAAC,CAAC;IAEtF,OAAO,MAAM,CAAC,oCAAoC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAY;IACvC,OAAO,CACL,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,WAAW;QACrB,KAAK,KAAK,UAAU;QACpB,KAAK,KAAK,OAAO,CAClB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAY;IACrC,OAAO,CACL,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,WAAW;QACrB,KAAK,KAAK,UAAU,CACrB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"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"}