@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,134 +1,355 @@
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
 
20
31
  import { html, unsafe, type RawHtml } from '../html.ts';
21
32
  import { scrapbookViewerUrl } from '../../components/scrapbook-item.ts';
22
33
  import type { Entry, Stage } from '@deskwork/core/schema/entry';
23
34
 
35
+ /** A single verb the operator can invoke from a row. */
36
+ interface Verb {
37
+ /** Internal kind — drives CSS accent class + glyph. */
38
+ readonly kind:
39
+ | 'iterate'
40
+ | 'approve'
41
+ | 'block'
42
+ | 'cancel'
43
+ | 'induct'
44
+ | 'view'
45
+ | 'scrapbook';
46
+ /** Display label for drawer chip + menu item. */
47
+ readonly label: string;
48
+ /** Single-character glyph. */
49
+ readonly glyph: string;
50
+ /**
51
+ * Either a `data-copy` payload (slash command — most verbs) or a `data-href`
52
+ * payload (URL — view, scrapbook). Mutually exclusive.
53
+ */
54
+ readonly copy?: string;
55
+ readonly href?: string;
56
+ /** Title attribute / accessibility hint. */
57
+ readonly title: string;
58
+ /** Optional compact label for swipe-drawer chip (cramped 64px width). */
59
+ readonly drawerLabel?: string;
60
+ }
61
+
24
62
  /**
25
- * Build the per-row action strip. Affordances vary by stage:
26
- *
27
- * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
28
- * "open →" link, "iterate →" copy-CLI button (always; no state gate),
29
- * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
30
- * - Final: "open →", "approve →" (graduates to Published; assigns a
31
- * version per the operator's scheme), "cancel ⊘". NO iterate
32
- * (Final locks content per the spec).
33
- * - Published: "view →" (read-only review surface). Future enhancement:
34
- * surface a "revise" affordance that inducts back to Drafting.
35
- * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
63
+ * Build the stage-aware verb set for an entry. Returns three views — the
64
+ * inline-chip set (desktop high-frequency verbs), the drawer set (mobile
65
+ * swipe top-N), and the menu set (full stage-aware vocabulary).
36
66
  *
37
- * All non-terminal stages also get a `scrapbook ↗` link (#157).
38
- *
39
- * Each button's behavior is parked behind a `data-copy` attribute so
40
- * the existing studio client (editorial-studio-client.ts) handles
41
- * clipboard wiring without new server handlers.
67
+ * Visibility-by-surface is intentional and documented in
68
+ * `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/brief.md`.
42
69
  */
43
- export function renderRowActions(entry: Entry, defaultSite: string): RawHtml {
44
- const buttons: string[] = [];
45
- const stage = entry.currentStage;
70
+ function verbsForStage(
71
+ stage: Stage,
72
+ entry: Entry,
73
+ defaultSite: string,
74
+ ): {
75
+ readonly inline: readonly Verb[];
76
+ readonly drawer: readonly Verb[];
77
+ readonly menu: readonly Verb[];
78
+ } {
79
+ const slug = entry.slug;
46
80
  const reviewLink = `/dev/editorial-review/entry/${entry.uuid}`;
47
- // Scrapbook URL uses the project's defaultSite. Multi-site calendars
48
- // would require a per-entry site lookup (out of scope for #157 — the
49
- // primary value is the dashboard ↔ scrapbook entry point existing at
50
- // all, and most projects have a single site). Slug already contains
51
- // any hierarchical path segments.
52
- //
53
- // #205: thread the entry's UUID through `scrapbookViewerUrl` so the
54
- // standalone viewer's server route resolves the listing via
55
- // `scrapbookDirForEntry` for entries whose on-disk path doesn't match
56
- // the slug template (e.g. feature-doc layouts under
57
- // `docs/<version>/<status>/<slug>/`). Falls back to slug-template
58
- // addressing for entries without an id binding.
81
+ // Scrapbook URL uses the project's defaultSite (#157, #205). Slug already
82
+ // contains any hierarchical segments.
59
83
  const scrapLink = scrapbookViewerUrl({
60
84
  site: defaultSite,
61
- path: entry.slug,
85
+ path: slug,
62
86
  entryId: entry.uuid,
63
87
  });
64
88
 
65
- if (isLinearActiveStage(stage)) {
66
- buttons.push(html`<a class="er-btn er-btn-small" href="${reviewLink}"
67
- title="open the review surface for ${entry.slug}">open →</a>`);
68
- // Iterate — stage-gated per DESKWORK-STATE-MACHINE.md Commandment II:
69
- // verbs are stage-gated, never state-gated. Iterate runs on stages
70
- // that permit edits (Ideas / Planned / Outlining / Drafting); Final
71
- // locks content so iterate is hidden there. The previous
72
- // `reviewState === 'iterating'` gate was a Commandment II violation;
73
- // removed in the v0.19 spec-conformance sweep.
74
- if (stagePermitsEdits(stage)) {
75
- buttons.push(html`<button class="er-btn er-btn-small er-btn-primary er-copy-btn" type="button"
76
- data-copy="/deskwork:iterate ${entry.slug}"
77
- title="operator clicked Iterate run the iterate skill in Claude Code">iterate →</button>`);
78
- }
79
- // Approve (#244) unconditional on active-pipeline rows. Mirrors
80
- // the review-surface decision strip (Approve is always visible
81
- // there); the dashboard previously gated this button on
82
- // `reviewState === 'approved'`, which is a transient state most
83
- // rows never carry, leaving the button effectively invisible. The
84
- // operator should be able to advance any active-pipeline entry
85
- // from the dashboard without first opening the review surface.
86
- buttons.push(html`<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
87
- data-copy="/deskwork:approve ${entry.slug}"
88
- title="advance this entry to the next stage">approve →</button>`);
89
- // Cancel (#242) — pull this entry off-pipeline. Same clipboard
90
- // routing as approve / iterate; the skill mutates sidecar + journal.
91
- buttons.push(html`<button class="er-btn er-btn-small er-btn-reject er-copy-btn" type="button"
92
- data-copy="/deskwork:cancel ${entry.slug}"
93
- title="pull this entry off-pipeline (Cancelled). Reversible via /deskwork:induct.">cancel ⊘</button>`);
94
- } else if (stage === 'Published') {
95
- buttons.push(html`<a class="er-btn er-btn-small" href="${reviewLink}"
96
- title="read-only review surface for the published entry">view →</a>`);
97
- } else if (stage === 'Blocked' || stage === 'Cancelled') {
98
- buttons.push(html`<button class="er-btn er-btn-small er-copy-btn" type="button"
99
- data-copy="/deskwork:induct ${entry.slug}"
100
- title="bring this entry back into the pipeline">induct →</button>`);
89
+ const iterate: Verb = {
90
+ kind: 'iterate',
91
+ label: 'Iterate',
92
+ glyph: '↻',
93
+ copy: `/deskwork:iterate ${slug}`,
94
+ title: 'append a new revision to this entry',
95
+ };
96
+ const approve: Verb = {
97
+ kind: 'approve',
98
+ label: stage === 'Final' ? 'Approve → Published' : 'Approve',
99
+ glyph: '✓',
100
+ // Per DESKWORK-STATE-MACHINE.md Commandment II, approve is universal
101
+ // across every linear-pipeline transition including Final Published.
102
+ // The `/deskwork:approve` skill handles all stage transitions; the
103
+ // separate `/deskwork:publish` skill is an alias for the Final →
104
+ // Published case, not a separate verb. Use approve uniformly.
105
+ copy: `/deskwork:approve ${slug}`,
106
+ title:
107
+ stage === 'Final'
108
+ ? 'advance this entry to Published (assigns a public version)'
109
+ : 'advance this entry to the next stage',
110
+ };
111
+ const block: Verb = {
112
+ kind: 'block',
113
+ label: 'Block (pause)',
114
+ glyph: '‖',
115
+ copy: `/deskwork:block ${slug}`,
116
+ title: 'pause this entry without abandoning it (reversible via /deskwork:induct)',
117
+ };
118
+ const induct: Verb = {
119
+ kind: 'induct',
120
+ label: 'Induct… (pick stage)',
121
+ glyph: '',
122
+ copy: `/deskwork:induct ${slug}`,
123
+ title: 'teleport this entry to a chosen stage (forward or backward)',
124
+ };
125
+ const cancel: Verb = {
126
+ kind: 'cancel',
127
+ label: 'Cancel',
128
+ glyph: '⊘',
129
+ copy: `/deskwork:cancel ${slug}`,
130
+ title: 'pull this entry off-pipeline (Cancelled; rarely resumed)',
131
+ };
132
+ const view: Verb = {
133
+ kind: 'view',
134
+ label: 'View',
135
+ glyph: '→',
136
+ href: reviewLink,
137
+ title: 'read-only review surface for the published entry',
138
+ };
139
+ const scrapbook: Verb = {
140
+ kind: 'scrapbook',
141
+ label: 'Open scrapbook',
142
+ glyph: '⊞',
143
+ href: scrapLink,
144
+ title: "open the entry's scrapbook (research notes, drafts, etc.)",
145
+ drawerLabel: 'Scrpbk',
146
+ };
147
+ // Used only on Blocked/Cancelled rows where induct's primary use is
148
+ // bringing the entry back into the pipeline.
149
+ const inductForward: Verb = {
150
+ ...induct,
151
+ label: 'Induct… (pick stage)',
152
+ title: 'bring this entry back into the pipeline',
153
+ };
154
+
155
+ if (stage === 'Ideas' || stage === 'Planned' || stage === 'Outlining' || stage === 'Drafting') {
156
+ return {
157
+ // Scrapbook stays inline on every stage — it's the entry's research
158
+ // surface, used at the same cadence as the active-stage verb.
159
+ inline: [iterate, approve, scrapbook],
160
+ drawer: [iterate, approve, cancel, scrapbook],
161
+ menu: [iterate, approve, block, induct, cancel, scrapbook],
162
+ };
163
+ }
164
+ if (stage === 'Final') {
165
+ return {
166
+ inline: [approve, scrapbook],
167
+ drawer: [approve, cancel, scrapbook],
168
+ menu: [approve, block, induct, cancel, scrapbook],
169
+ };
170
+ }
171
+ if (stage === 'Blocked' || stage === 'Cancelled') {
172
+ return {
173
+ inline: [inductForward, scrapbook],
174
+ drawer: [inductForward, scrapbook],
175
+ menu: [inductForward, scrapbook],
176
+ };
177
+ }
178
+ if (stage === 'Published') {
179
+ // Frozen artifact; view + scrapbook only.
180
+ return {
181
+ inline: [view, scrapbook],
182
+ drawer: [view, scrapbook],
183
+ menu: [view, scrapbook],
184
+ };
185
+ }
186
+ // Exhaustiveness check — if the Stage union gains a new variant, the
187
+ // assertion will fail at typecheck time and at runtime so we don't
188
+ // silently fall through to an empty verb set.
189
+ const _exhaustive: never = stage;
190
+ throw new Error(`verbsForStage: unhandled stage "${String(_exhaustive)}"`);
191
+ }
192
+
193
+ function renderDrawerChip(verb: Verb): string {
194
+ const labelText = verb.drawerLabel ?? verb.label.split(' ')[0];
195
+ // Route the data attribute through the html tag so its value is
196
+ // properly attribute-escaped. Slug regex constrains the payload today
197
+ // (no unbalanced quotes possible) but future-verb churn could land a
198
+ // payload with HTML-sensitive characters; the tag handles them.
199
+ if (verb.copy !== undefined) {
200
+ return html`<button type="button"
201
+ class="er-row-action er-row-action-${verb.kind}"
202
+ data-copy="${verb.copy}"
203
+ title="${verb.title}">
204
+ <span class="er-row-action-glyph" aria-hidden="true">${verb.glyph}</span>
205
+ <span class="er-row-action-label">${labelText}</span>
206
+ </button>`;
101
207
  }
208
+ return html`<button type="button"
209
+ class="er-row-action er-row-action-${verb.kind}"
210
+ data-href="${verb.href ?? ''}"
211
+ title="${verb.title}">
212
+ <span class="er-row-action-glyph" aria-hidden="true">${verb.glyph}</span>
213
+ <span class="er-row-action-label">${labelText}</span>
214
+ </button>`;
215
+ }
102
216
 
103
- // Scrapbook link follows every stage's primary action.
104
- buttons.push(html`<a class="er-btn er-btn-small er-btn-scrap"
105
- href="${scrapLink}" data-action="open-scrapbook"
106
- title="open the entry's scrapbook (research notes, drafts, etc.)">scrapbook ↗</a>`);
217
+ function renderInlineChip(verb: Verb): string {
218
+ // Inline chips are the high-frequency desktop affordances. View +
219
+ // scrapbook render as plain links (no clipboard); the rest are
220
+ // clipboard-copy buttons routing slash commands. Scrapbook links
221
+ // also carry `data-action="open-scrapbook"` so the existing client
222
+ // can distinguish them from review-surface links (#157, #205).
223
+ if (verb.href !== undefined) {
224
+ const dataAction = verb.kind === 'scrapbook' ? ' data-action="open-scrapbook"' : '';
225
+ return html`<a class="er-btn-chip er-btn-chip-${verb.kind}"
226
+ href="${verb.href}"${unsafe(dataAction)} title="${verb.title}">${verb.label} ${verb.glyph}</a>`;
227
+ }
228
+ return html`<button type="button"
229
+ class="er-btn-chip er-btn-chip-${verb.kind} er-copy-btn"
230
+ data-copy="${verb.copy ?? ''}"
231
+ title="${verb.title}">${verb.label.toLowerCase()} ${verb.glyph}</button>`;
232
+ }
107
233
 
108
- return unsafe(`<span class="er-calendar-action">${buttons.join('')}</span>`);
234
+ function renderMenuItem(verb: Verb): string {
235
+ // Short command hint matching the mockup's compact form:
236
+ // copy verbs → `/deskwork:approve` (verb only, no slug)
237
+ // href verbs → `/dev/scrapbook` / `/dev/editorial-review` (path stem,
238
+ // no site / uuid / query string)
239
+ // The clipboard-copy still routes the FULL slash command via data-copy;
240
+ // hrefs still navigate to the full URL via data-href. The hint is just a
241
+ // visual reminder of which command/route is being invoked — appending the
242
+ // slug / full path doubles the cmd cell width and forces the label to
243
+ // wrap on narrow viewports.
244
+ const cmdHint = verb.copy !== undefined
245
+ ? verb.copy.split(' ', 1)[0]
246
+ : (verb.href ?? '').split('/').slice(0, 3).join('/');
247
+ // Route data attributes through the html tag for proper escaping.
248
+ if (verb.href !== undefined) {
249
+ return html`<button type="button"
250
+ class="er-row-menu-item"
251
+ role="menuitem"
252
+ data-href="${verb.href}"
253
+ title="${verb.title}">
254
+ <span class="er-row-menu-glyph er-row-menu-glyph-${verb.kind}" aria-hidden="true">${verb.glyph}</span>
255
+ <span class="er-row-menu-label">${verb.label}</span>
256
+ <span class="er-row-menu-cmd">${cmdHint}</span>
257
+ </button>`;
258
+ }
259
+ return html`<button type="button"
260
+ class="er-row-menu-item"
261
+ role="menuitem"
262
+ data-copy="${verb.copy ?? ''}"
263
+ title="${verb.title}">
264
+ <span class="er-row-menu-glyph er-row-menu-glyph-${verb.kind}" aria-hidden="true">${verb.glyph}</span>
265
+ <span class="er-row-menu-label">${verb.label}</span>
266
+ <span class="er-row-menu-cmd">${cmdHint}</span>
267
+ </button>`;
109
268
  }
110
269
 
111
- function isLinearActiveStage(stage: Stage): boolean {
112
- return (
113
- stage === 'Ideas' ||
114
- stage === 'Planned' ||
115
- stage === 'Outlining' ||
116
- stage === 'Drafting' ||
117
- stage === 'Final'
118
- );
270
+ /**
271
+ * Group menu items per the mockup's visual rhythm:
272
+ * primary verbs · divider · secondary (block / induct) · divider · off-pipeline
273
+ *
274
+ * For Blocked/Cancelled/Published the menu is short enough to skip dividers.
275
+ */
276
+ function renderMenu(stage: Stage, menu: readonly Verb[]): string {
277
+ const isShort = stage === 'Blocked' || stage === 'Cancelled' || stage === 'Published';
278
+ if (isShort) {
279
+ return menu.map(renderMenuItem).join('');
280
+ }
281
+ // Active + Final use grouped layout.
282
+ const primary: Verb[] = [];
283
+ const secondary: Verb[] = [];
284
+ const tail: Verb[] = [];
285
+ for (const v of menu) {
286
+ if (v.kind === 'iterate' || v.kind === 'approve') primary.push(v);
287
+ else if (v.kind === 'block' || v.kind === 'induct') secondary.push(v);
288
+ else tail.push(v);
289
+ }
290
+ const divider = '<hr class="er-row-menu-divider" role="separator" />';
291
+ return [
292
+ ...primary.map(renderMenuItem),
293
+ primary.length > 0 && secondary.length > 0 ? divider : '',
294
+ ...secondary.map(renderMenuItem),
295
+ secondary.length > 0 && tail.length > 0 ? divider : '',
296
+ ...tail.map(renderMenuItem),
297
+ ]
298
+ .filter(Boolean)
299
+ .join('');
300
+ }
301
+
302
+ /**
303
+ * Render the row's affordance chrome — drawer + inline chips + ⋮ button.
304
+ *
305
+ * Returned HTML expects to be embedded inside the row's foreground container
306
+ * (`.er-row-fg`). The drawer + menu live as siblings of `.er-row-fg` inside
307
+ * `.er-row-shell`; section.ts owns that outer composition.
308
+ *
309
+ * Three pieces:
310
+ * 1. Inline chips — high-frequency verbs as outlined chips (desktop only;
311
+ * CSS hides them on mobile).
312
+ * 2. Overflow `⋮` button — toggles the menu popover. Visible on both
313
+ * mobile and desktop.
314
+ *
315
+ * Drawer + menu are rendered separately via `renderRowDrawer` and
316
+ * `renderRowMenu` (also exported) so section.ts can place them in the
317
+ * correct outer layout (drawer is sibling of `.er-row-fg`; menu is sibling
318
+ * of `.er-row-fg`).
319
+ */
320
+ export function renderRowActions(entry: Entry, defaultSite: string): RawHtml {
321
+ const { inline } = verbsForStage(entry.currentStage, entry, defaultSite);
322
+ const chips = inline.map(renderInlineChip).join('');
323
+ const overflow = html`<button type="button"
324
+ class="er-row-overflow"
325
+ data-row-overflow
326
+ aria-haspopup="menu"
327
+ aria-expanded="false"
328
+ aria-label="More actions">⋮</button>`;
329
+ // Keep `.er-calendar-action` as the wrapper class so the existing
330
+ // mobile grid-template-areas (`action` area at row 3 of the row
331
+ // grid) and desktop layout rules continue to position the chrome.
332
+ // The `.er-row-affordances` class is added alongside as a v0.20
333
+ // marker for any future rules that need to target the new chrome
334
+ // specifically.
335
+ return unsafe(`<span class="er-calendar-action er-row-affordances">${chips}${overflow}</span>`);
336
+ }
337
+
338
+ /**
339
+ * Drawer rendered as a sibling of `.er-row-fg`. Absolute-positioned at the
340
+ * row's trailing edge; hidden behind the foreground at-rest. Revealed by
341
+ * the foreground translating left on swipe.
342
+ */
343
+ export function renderRowDrawer(entry: Entry, defaultSite: string): RawHtml {
344
+ const { drawer } = verbsForStage(entry.currentStage, entry, defaultSite);
345
+ return unsafe(html`<div class="er-row-drawer" aria-hidden="true">${unsafe(drawer.map(renderDrawerChip).join(''))}</div>`);
119
346
  }
120
347
 
121
348
  /**
122
- * Stages that permit content edits (and therefore iterate). Final
123
- * locks content per DESKWORK-STATE-MACHINE.md iterate refuses there;
124
- * the operator must induct backward to a stage that permits edits if
125
- * they want to revise a Final entry.
349
+ * Menu popover rendered as a sibling of `.er-row-fg`. Hidden by default
350
+ * (the controller flips `hidden` + `aria-expanded` on the overflow button).
126
351
  */
127
- function stagePermitsEdits(stage: Stage): boolean {
128
- return (
129
- stage === 'Ideas' ||
130
- stage === 'Planned' ||
131
- stage === 'Outlining' ||
132
- stage === 'Drafting'
133
- );
352
+ export function renderRowMenu(entry: Entry, defaultSite: string): RawHtml {
353
+ const { menu } = verbsForStage(entry.currentStage, entry, defaultSite);
354
+ return unsafe(html`<div class="er-row-menu" role="menu" hidden>${unsafe(renderMenu(entry.currentStage, menu))}</div>`);
134
355
  }
@@ -1 +1 @@
1
- {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAyBhE;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CA2BnF;AAgCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAkCT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAsBvD"}
1
+ {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAyBhE;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAgDnF;AAgCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAkCT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAsBvD"}
@@ -14,7 +14,7 @@
14
14
  * `<h2 class="er-section-head">` heading carries the stage name.
15
15
  */
16
16
  import { html, unsafe } from "../html.js";
17
- import { renderRowActions } from "./affordances.js";
17
+ import { renderRowActions, renderRowDrawer, renderRowMenu } from "./affordances.js";
18
18
  const STAGE_ORNAMENTS = {
19
19
  Ideas: '◇',
20
20
  Planned: '§',
@@ -57,10 +57,30 @@ export function renderRow(entry, index, defaultSite) {
57
57
  const depthAttrs = depth > 0
58
58
  ? unsafe(html ` data-depth="${depth}" style="--er-row-depth: ${depth}"`)
59
59
  : '';
60
+ // Row composition (v0.20 redesign — ACCEPTED archive entry
61
+ // `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/`):
62
+ // <er-row-shell data-row-shell>
63
+ // <er-row-drawer/> ← absolute-positioned, hidden at-rest;
64
+ // revealed by swipe-left translating row-fg.
65
+ // <er-row-fg> ← visible foreground.
66
+ // <er-row-num/>
67
+ // <er-calendar-body/> ← slug + title + date
68
+ // <er-row-affordances/> ← inline chips (desktop) + ⋮ button
69
+ // </er-row-fg>
70
+ // <er-row-menu/> ← absolute-positioned popover anchored to ⋮.
71
+ // </er-row-shell>
72
+ // Client controller `row-actions.ts` wires the swipe gesture + menu state.
73
+ // data-* attrs (search/stage/uuid/slug) live on the SHELL only —
74
+ // the shell is the affordance boundary now. Existing filter +
75
+ // probe code targets `.er-calendar-row` so the legacy class stays
76
+ // on `.er-row-fg`, but the canonical attribute carriers are on the
77
+ // shell. Test selectors should prefer `[data-row-shell]`.
60
78
  return unsafe(html `
61
- <div class="er-calendar-row-wrap" data-row-wrap data-search="${search}"${depthAttrs}>
62
- <div class="er-calendar-row" data-stage="${entry.currentStage}"
63
- data-uuid="${entry.uuid}" data-slug="${entry.slug}" data-search="${search}">
79
+ <div class="er-row-shell" data-row-shell data-search="${search}"${depthAttrs}
80
+ data-stage="${entry.currentStage}"
81
+ data-uuid="${entry.uuid}" data-slug="${entry.slug}">
82
+ ${renderRowDrawer(entry, defaultSite)}
83
+ <div class="er-row-fg er-calendar-row">
64
84
  <span class="er-row-num">№ ${String(index + 1).padStart(2, '0')}</span>
65
85
  <div class="er-calendar-body">
66
86
  <span class="er-row-slug"><a href="${reviewLink}"
@@ -72,6 +92,7 @@ export function renderRow(entry, index, defaultSite) {
72
92
  <span class="er-calendar-status" aria-hidden="true"></span>
73
93
  ${renderRowActions(entry, defaultSite)}
74
94
  </div>
95
+ ${renderRowMenu(entry, defaultSite)}
75
96
  </div>`);
76
97
  }
77
98
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"section.js","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,eAAe,GAA0B;IAC7C,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,GAAG;IACb,KAAK,EAAE,GAAG;IACV,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;CACf,CAAC;AAEF,MAAM,oBAAoB,GAA0B;IAClD,KAAK,EAAE,kDAAkD;IACzD,OAAO,EAAE,gEAAgE;IACzE,SAAS,EAAE,uBAAuB;IAClC,QAAQ,EAAE,uBAAuB;IACjC,KAAK,EAAE,0BAA0B;IACjC,SAAS,EAAE,yBAAyB;IACpC,OAAO,EAAE,kBAAkB;IAC3B,SAAS,EAAE,uBAAuB;CACnC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CAAC,KAAY,EAAE,KAAa,EAAE,WAAmB;IACxE,MAAM,UAAU,GAAG,+BAA+B,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3F,kEAAkE;IAClE,wEAAwE;IACxE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/C,MAAM,UAAU,GACd,KAAK,GAAG,CAAC;QACP,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA,gBAAgB,KAAK,4BAA4B,KAAK,GAAG,CAAC;QACvE,CAAC,CAAC,EAAE,CAAC;IAET,OAAO,MAAM,CAAC,IAAI,CAAA;mEAC+C,MAAM,IAAI,UAAU;iDACtC,KAAK,CAAC,YAAY;qBAC9C,KAAK,CAAC,IAAI,gBAAgB,KAAK,CAAC,IAAI,kBAAkB,MAAM;qCAC5C,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;;+CAExB,UAAU;8CACX,KAAK,CAAC,IAAI;4CACZ,KAAK,CAAC,KAAK;;wBAE/B,KAAK,CAAC,SAAS,YAAY,KAAK,CAAC,SAAS,KAAK,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC;;;UAGxF,gBAAgB,CAAC,KAAK,EAAE,WAAW,CAAC;;WAEnC,CAAC,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,eAAe,CAAC,KAAY,EAAE,KAAa;IAClD,MAAM,OAAO,GAAG,KAAK,KAAK,CAAC,CAAC;IAC5B,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,eAAe,CAAC;IACrE,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,OAAO,MAAM,CAAC,IAAI,CAAA;qBACC,OAAO;yBACH,KAAK;;6BAED,KAAK,CAAC,WAAW,EAAE,IAAI,MAAM,CAAC,YAAY,CAAC;6DACX,eAAe,CAAC,KAAK,CAAC;yCAC1C,KAAK;4DACc,KAAK;;cAEnD,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAY,EACZ,OAAyB,EACzB,WAAmB;IAEnB,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC,IAAI,CAAA;sDACgC,KAAK;UACjD,IAAI;;sBAEQ,KAAK,CAAC,WAAW,EAAE,yBAAyB,KAAK;8BACzC,KAAK;;qBAEd,oBAAoB,CAAC,KAAK,CAAC;oBAC5B,KAAK;qCACY,eAAe,CAAC,KAAK,CAAC;;;;aAI9C,CAAC,CAAC;IACb,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAExF,OAAO,MAAM,CAAC,IAAI,CAAA;oDACgC,KAAK;QACjD,IAAI;8CACkC,KAAK,CAAC,WAAW,EAAE,yBAAyB,KAAK;;kBAE7E,KAAK;mCACY,eAAe,CAAC,KAAK,CAAC;kCACvB,OAAO,CAAC,MAAM;;UAEtC,IAAI;;WAEH,CAAC,CAAC;AACb,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,6BAA6B;IAC3C,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;WAoBT,CAAC,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,mEAAmE;IACnE,sBAAsB;IACtB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1B,CAAC"}
1
+ {"version":3,"file":"section.js","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { html, unsafe, type RawHtml } from '../html.ts';
18
18
  import type { Entry, Stage } from '@deskwork/core/schema/entry';
19
- import { renderRowActions } from './affordances.ts';
19
+ import { renderRowActions, renderRowDrawer, renderRowMenu } from './affordances.ts';
20
20
 
21
21
  const STAGE_ORNAMENTS: Record<Stage, string> = {
22
22
  Ideas: '◇',
@@ -64,10 +64,30 @@ export function renderRow(entry: Entry, index: number, defaultSite: string): Raw
64
64
  ? unsafe(html` data-depth="${depth}" style="--er-row-depth: ${depth}"`)
65
65
  : '';
66
66
 
67
+ // Row composition (v0.20 redesign — ACCEPTED archive entry
68
+ // `docs/studio-design/ACCEPTED/2026-05-11-row-affordance-overflow-plus-swipe/`):
69
+ // <er-row-shell data-row-shell>
70
+ // <er-row-drawer/> ← absolute-positioned, hidden at-rest;
71
+ // revealed by swipe-left translating row-fg.
72
+ // <er-row-fg> ← visible foreground.
73
+ // <er-row-num/>
74
+ // <er-calendar-body/> ← slug + title + date
75
+ // <er-row-affordances/> ← inline chips (desktop) + ⋮ button
76
+ // </er-row-fg>
77
+ // <er-row-menu/> ← absolute-positioned popover anchored to ⋮.
78
+ // </er-row-shell>
79
+ // Client controller `row-actions.ts` wires the swipe gesture + menu state.
80
+ // data-* attrs (search/stage/uuid/slug) live on the SHELL only —
81
+ // the shell is the affordance boundary now. Existing filter +
82
+ // probe code targets `.er-calendar-row` so the legacy class stays
83
+ // on `.er-row-fg`, but the canonical attribute carriers are on the
84
+ // shell. Test selectors should prefer `[data-row-shell]`.
67
85
  return unsafe(html`
68
- <div class="er-calendar-row-wrap" data-row-wrap data-search="${search}"${depthAttrs}>
69
- <div class="er-calendar-row" data-stage="${entry.currentStage}"
70
- data-uuid="${entry.uuid}" data-slug="${entry.slug}" data-search="${search}">
86
+ <div class="er-row-shell" data-row-shell data-search="${search}"${depthAttrs}
87
+ data-stage="${entry.currentStage}"
88
+ data-uuid="${entry.uuid}" data-slug="${entry.slug}">
89
+ ${renderRowDrawer(entry, defaultSite)}
90
+ <div class="er-row-fg er-calendar-row">
71
91
  <span class="er-row-num">№ ${String(index + 1).padStart(2, '0')}</span>
72
92
  <div class="er-calendar-body">
73
93
  <span class="er-row-slug"><a href="${reviewLink}"
@@ -79,6 +99,7 @@ export function renderRow(entry: Entry, index: number, defaultSite: string): Raw
79
99
  <span class="er-calendar-status" aria-hidden="true"></span>
80
100
  ${renderRowActions(entry, defaultSite)}
81
101
  </div>
102
+ ${renderRowMenu(entry, defaultSite)}
82
103
  </div>`);
83
104
  }
84
105
 
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC;AAElE;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,MAAM,CAAC,CA0CjB"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,YAAY,CAAC;AAElE;;;GAGG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,QAAQ,CAAC,EAAE,oBAAoB,GAC9B,OAAO,CAAC,MAAM,CAAC,CA2CjB"}
@@ -73,6 +73,7 @@ export async function renderDashboard(ctx, getIndex) {
73
73
  '/static/css/editorial-nav.css',
74
74
  '/static/css/editorial-studio.css',
75
75
  '/static/css/dashboard-mobile.css',
76
+ '/static/css/dashboard-row-affordances.css',
76
77
  ],
77
78
  bodyAttrs: 'data-review-ui="studio"',
78
79
  bodyHtml: body,
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAWxE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,QAA+B;IAE/B,iEAAiE;IACjE,KAAK,QAAQ,CAAC;IAEd,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC9D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,+DAA+D;IAC/D,8DAA8D;IAC9D,4DAA4D;IAC5D,+EAA+E;IAC/E,0BAA0B;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAA;IACf,oBAAoB,CAAC,WAAW,EAAE,aAAa,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC;;MAEtC,iBAAiB,EAAE;MACnB,MAAM,CAAC,aAAa,CAAC;MACrB,6BAA6B,EAAE;;IAEjC,mBAAmB,EAAE;;oEAE2C,CAAC;IAEnE,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,kCAAkC;YAClC,+BAA+B;YAC/B,kCAAkC;YAClC,kCAAkC;SACnC;QACD,SAAS,EAAE,yBAAyB;QACpC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,CAAC,yBAAyB,CAAC;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,mBAAmB;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsDP,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/pages/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAWxE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,QAA+B;IAE/B,iEAAiE;IACjE,KAAK,QAAQ,CAAC;IAEd,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7C,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;IAC3C,MAAM,aAAa,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC;IAC9D,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,+DAA+D;IAC/D,8DAA8D;IAC9D,4DAA4D;IAC5D,+EAA+E;IAC/E,0BAA0B;IAC1B,MAAM,IAAI,GAAG,IAAI,CAAA;IACf,oBAAoB,CAAC,WAAW,EAAE,aAAa,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC;;MAEtC,iBAAiB,EAAE;MACnB,MAAM,CAAC,aAAa,CAAC;MACrB,6BAA6B,EAAE;;IAEjC,mBAAmB,EAAE;;oEAE2C,CAAC;IAEnE,OAAO,MAAM,CAAC;QACZ,KAAK,EAAE,mBAAmB;QAC1B,QAAQ,EAAE;YACR,kCAAkC;YAClC,+BAA+B;YAC/B,kCAAkC;YAClC,kCAAkC;YAClC,2CAA2C;SAC5C;QACD,SAAS,EAAE,yBAAyB;QACpC,QAAQ,EAAE,IAAI;QACd,aAAa,EAAE,CAAC,yBAAyB,CAAC;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,mBAAmB;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aAsDP,CAAC,CAAC;AACf,CAAC"}
@@ -95,6 +95,7 @@ export async function renderDashboard(
95
95
  '/static/css/editorial-nav.css',
96
96
  '/static/css/editorial-studio.css',
97
97
  '/static/css/dashboard-mobile.css',
98
+ '/static/css/dashboard-row-affordances.css',
98
99
  ],
99
100
  bodyAttrs: 'data-review-ui="studio"',
100
101
  bodyHtml: body,