@deskwork/studio 0.19.0 → 0.20.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.
- package/dist/pages/dashboard/affordances.d.ts +49 -28
- package/dist/pages/dashboard/affordances.d.ts.map +1 -1
- package/dist/pages/dashboard/affordances.js +288 -102
- package/dist/pages/dashboard/affordances.js.map +1 -1
- package/dist/pages/dashboard/affordances.ts +327 -106
- package/dist/pages/dashboard/section.d.ts.map +1 -1
- package/dist/pages/dashboard/section.js +25 -4
- package/dist/pages/dashboard/section.js.map +1 -1
- package/dist/pages/dashboard/section.ts +25 -4
- package/dist/pages/dashboard.d.ts.map +1 -1
- package/dist/pages/dashboard.js +1 -0
- package/dist/pages/dashboard.js.map +1 -1
- package/dist/pages/dashboard.ts +1 -0
- package/package.json +2 -2
|
@@ -1,41 +1,62 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-row affordance
|
|
2
|
+
* Per-row affordance rendering for the dashboard.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* on
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
-
*
|
|
33
|
+
* Render the row's affordance chrome — drawer + inline chips + ⋮ button.
|
|
23
34
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
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
|
|
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
|
|
2
|
+
* Per-row affordance rendering for the dashboard.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* on
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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
|
-
*
|
|
37
|
-
*
|
|
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
|
-
|
|
41
|
-
const
|
|
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.
|
|
45
|
-
//
|
|
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:
|
|
47
|
+
path: slug,
|
|
59
48
|
entryId: entry.uuid,
|
|
60
49
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
title="
|
|
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
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
*
|
|
115
|
-
*
|
|
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
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
1
|
+
{"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,134 +1,355 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Per-row affordance
|
|
2
|
+
* Per-row affordance rendering for the dashboard.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* on
|
|
13
|
-
*
|
|
14
|
-
* -
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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.
|
|
48
|
-
//
|
|
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:
|
|
85
|
+
path: slug,
|
|
62
86
|
entryId: entry.uuid,
|
|
63
87
|
});
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
*
|
|
123
|
-
*
|
|
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
|
|
128
|
-
|
|
129
|
-
|
|
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,
|
|
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-
|
|
62
|
-
|
|
63
|
-
|
|
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;
|
|
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-
|
|
69
|
-
|
|
70
|
-
|
|
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,
|
|
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"}
|
package/dist/pages/dashboard.js
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/pages/dashboard.ts
CHANGED
|
@@ -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,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deskwork/studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Editorial review studio — local web UI for the deskwork plugin",
|
|
6
6
|
"homepage": "https://github.com/audiocontrol-org/deskwork#readme",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"@codemirror/language": "^6.12.3",
|
|
47
47
|
"@codemirror/state": "^6.6.0",
|
|
48
48
|
"@codemirror/view": "^6.41.1",
|
|
49
|
-
"@deskwork/core": "0.
|
|
49
|
+
"@deskwork/core": "0.20.0",
|
|
50
50
|
"@hono/node-server": "^1.13.7",
|
|
51
51
|
"@lezer/highlight": "^1.2.3",
|
|
52
52
|
"esbuild": "^0.28.0",
|