@deskwork/studio 0.20.0 → 0.22.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/adjacent-section.d.ts +38 -0
- package/dist/pages/dashboard/adjacent-section.d.ts.map +1 -0
- package/dist/pages/dashboard/adjacent-section.js +61 -0
- package/dist/pages/dashboard/adjacent-section.js.map +1 -0
- package/dist/pages/dashboard/adjacent-section.ts +71 -0
- package/dist/pages/dashboard/data.d.ts +35 -4
- package/dist/pages/dashboard/data.d.ts.map +1 -1
- package/dist/pages/dashboard/data.js +69 -5
- package/dist/pages/dashboard/data.js.map +1 -1
- package/dist/pages/dashboard/data.ts +84 -5
- package/dist/pages/dashboard/section.d.ts.map +1 -1
- package/dist/pages/dashboard/section.js +7 -0
- package/dist/pages/dashboard/section.js.map +1 -1
- package/dist/pages/dashboard/section.ts +7 -0
- package/dist/pages/dashboard/shortform-section.d.ts +86 -0
- package/dist/pages/dashboard/shortform-section.d.ts.map +1 -0
- package/dist/pages/dashboard/shortform-section.js +189 -0
- package/dist/pages/dashboard/shortform-section.js.map +1 -0
- package/dist/pages/dashboard/shortform-section.ts +228 -0
- package/dist/pages/dashboard.d.ts.map +1 -1
- package/dist/pages/dashboard.js +34 -1
- package/dist/pages/dashboard.js.map +1 -1
- package/dist/pages/dashboard.ts +40 -1
- package/dist/pages/entry-review/index.d.ts.map +1 -1
- package/dist/pages/entry-review/index.js +24 -2
- package/dist/pages/entry-review/index.js.map +1 -1
- package/dist/pages/entry-review/mobile-sheet.d.ts +65 -0
- package/dist/pages/entry-review/mobile-sheet.d.ts.map +1 -0
- package/dist/pages/entry-review/mobile-sheet.js +170 -0
- package/dist/pages/entry-review/mobile-sheet.js.map +1 -0
- package/dist/pages/masthead-menu.d.ts +38 -0
- package/dist/pages/masthead-menu.d.ts.map +1 -0
- package/dist/pages/masthead-menu.js +126 -0
- package/dist/pages/masthead-menu.js.map +1 -0
- package/dist/pages/masthead-menu.ts +128 -0
- package/dist/pages/masthead.d.ts +85 -0
- package/dist/pages/masthead.d.ts.map +1 -0
- package/dist/pages/masthead.js +99 -0
- package/dist/pages/masthead.js.map +1 -0
- package/dist/pages/masthead.ts +155 -0
- package/dist/pages/mobile-bar.d.ts +72 -0
- package/dist/pages/mobile-bar.d.ts.map +1 -0
- package/dist/pages/mobile-bar.js +88 -0
- package/dist/pages/mobile-bar.js.map +1 -0
- package/dist/pages/mobile-bar.ts +129 -0
- package/dist/pages/shortform-review-mobile-sheet.d.ts +76 -0
- package/dist/pages/shortform-review-mobile-sheet.d.ts.map +1 -0
- package/dist/pages/shortform-review-mobile-sheet.js +159 -0
- package/dist/pages/shortform-review-mobile-sheet.js.map +1 -0
- package/dist/pages/shortform-review-mobile-sheet.ts +185 -0
- package/dist/pages/shortform-review.d.ts +18 -0
- package/dist/pages/shortform-review.d.ts.map +1 -1
- package/dist/pages/shortform-review.js +62 -111
- package/dist/pages/shortform-review.js.map +1 -1
- package/dist/pages/shortform-review.ts +68 -140
- package/dist/pages/shortform.d.ts.map +1 -1
- package/dist/pages/shortform.js +0 -1
- package/dist/pages/shortform.js.map +1 -1
- package/dist/pages/shortform.ts +0 -1
- package/dist/server.js +41 -1
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortform-review-specific mobile sheet host + bar cell composition.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `entry-review/mobile-sheet.ts` for the shortform review
|
|
5
|
+
* surface. The mobile-bar primitive (`../mobile-bar.ts`) is universal;
|
|
6
|
+
* each surface composes its `Cell[]` and the corresponding slot host
|
|
7
|
+
* here.
|
|
8
|
+
*
|
|
9
|
+
* Design contract (DESIGN-STANDARDS.md § Universal bar contract,
|
|
10
|
+
* settled 2026-05-13):
|
|
11
|
+
* - One bar primitive, one shape. The per-surface design variable
|
|
12
|
+
* is the cells, not the chrome.
|
|
13
|
+
* - 1-6 contextual cells. The Actions cell is unconditional so the
|
|
14
|
+
* bar is never empty (renderMobileBar throws on empty cells).
|
|
15
|
+
* - The TOC and Versions cells are conditional (hidden when their
|
|
16
|
+
* content has fewer than 2 items).
|
|
17
|
+
*
|
|
18
|
+
* State-machine compliance (DESKWORK-STATE-MACHINE.md):
|
|
19
|
+
* - Commandment II: verbs are universal. Approve/Iterate/Cancel are
|
|
20
|
+
* rendered unconditionally inside the Actions slot. The shortform
|
|
21
|
+
* surface header (shortform-review.ts:1-18) explicitly defers the
|
|
22
|
+
* legacy `DraftWorkflowState` migration; for this step we surface
|
|
23
|
+
* the three universal verbs and trust the client clipboard handlers
|
|
24
|
+
* to compose the right slash command from the workflow context.
|
|
25
|
+
* - Commandment III: no review-state surfacing. No "IN REVIEW" /
|
|
26
|
+
* "ITERATING" / "APPROVED" pills. No `.er-stamp`. No
|
|
27
|
+
* `.er-pending-state` markup.
|
|
28
|
+
* - Commandment IV/V/VII: clipboard-copy is the only action. The
|
|
29
|
+
* three buttons carry `data-action="approve|iterate|cancel"`; the
|
|
30
|
+
* existing client handlers in `editorial-review-client.ts` wire
|
|
31
|
+
* them to clipboard-only handlers (post-G.3 refactor).
|
|
32
|
+
* - G.4 (issue #260): the destructive verb is `cancel`, NOT `reject`.
|
|
33
|
+
* The state machine has no `reject` verb.
|
|
34
|
+
*/
|
|
35
|
+
import type { TocEntry } from '@deskwork/core/review/toc';
|
|
36
|
+
import type { DraftVersion, DraftWorkflowItem } from '@deskwork/core/review/types';
|
|
37
|
+
import { type RawHtml } from './html.ts';
|
|
38
|
+
import type { Cell } from './mobile-bar.ts';
|
|
39
|
+
export interface ShortformBarCellOptions {
|
|
40
|
+
readonly tocEntries: readonly TocEntry[];
|
|
41
|
+
readonly versions: readonly DraftVersion[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the shortform review bar's contextual cell list.
|
|
45
|
+
*
|
|
46
|
+
* Cell ordering (when present): TOC → Versions → Actions. The Actions
|
|
47
|
+
* cell is always last and always present; the bar is never empty.
|
|
48
|
+
*
|
|
49
|
+
* Conditional-omission rules:
|
|
50
|
+
* - TOC cell: omitted when fewer than 2 heading entries exist.
|
|
51
|
+
* Shortform drafts (social-platform copy) are often headingless;
|
|
52
|
+
* surfacing an empty TOC adds noise without value per the
|
|
53
|
+
* "structure over scrolling" principle.
|
|
54
|
+
* - Versions cell: omitted when only one revision exists. With one
|
|
55
|
+
* revision there is no history to navigate.
|
|
56
|
+
*/
|
|
57
|
+
export declare function getShortformBarCells(opts: ShortformBarCellOptions): readonly Cell[];
|
|
58
|
+
export interface ShortformMobileSheetOptions {
|
|
59
|
+
readonly tocEntries: readonly TocEntry[];
|
|
60
|
+
readonly versions: readonly DraftVersion[];
|
|
61
|
+
readonly workflow: DraftWorkflowItem;
|
|
62
|
+
readonly currentVersion: DraftVersion;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Render the shortform mobile sheet host with the three named slots
|
|
66
|
+
* (toc / versions / actions). Each slot body is server-rendered so
|
|
67
|
+
* the client doesn't need to clone DOM from elsewhere on the page —
|
|
68
|
+
* the slot is self-contained.
|
|
69
|
+
*
|
|
70
|
+
* The sheet host is always rendered (matches the entry-review pattern
|
|
71
|
+
* where the host is present and the client toggles `hidden` on
|
|
72
|
+
* dispatch). Individual slots are hidden until the corresponding bar
|
|
73
|
+
* cell opens them via the shared `sheet-controller` primitive.
|
|
74
|
+
*/
|
|
75
|
+
export declare function renderShortformMobileSheet(opts: ShortformMobileSheetOptions): RawHtml;
|
|
76
|
+
//# sourceMappingURL=shortform-review-mobile-sheet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortform-review-mobile-sheet.d.ts","sourceRoot":"","sources":["../../src/pages/shortform-review-mobile-sheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EAClB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAA4B,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;CAC5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,uBAAuB,GAAG,SAAS,IAAI,EAAE,CAyBnF;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,UAAU,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAC;CACvC;AAiDD;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CA4BT"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortform-review-specific mobile sheet host + bar cell composition.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `entry-review/mobile-sheet.ts` for the shortform review
|
|
5
|
+
* surface. The mobile-bar primitive (`../mobile-bar.ts`) is universal;
|
|
6
|
+
* each surface composes its `Cell[]` and the corresponding slot host
|
|
7
|
+
* here.
|
|
8
|
+
*
|
|
9
|
+
* Design contract (DESIGN-STANDARDS.md § Universal bar contract,
|
|
10
|
+
* settled 2026-05-13):
|
|
11
|
+
* - One bar primitive, one shape. The per-surface design variable
|
|
12
|
+
* is the cells, not the chrome.
|
|
13
|
+
* - 1-6 contextual cells. The Actions cell is unconditional so the
|
|
14
|
+
* bar is never empty (renderMobileBar throws on empty cells).
|
|
15
|
+
* - The TOC and Versions cells are conditional (hidden when their
|
|
16
|
+
* content has fewer than 2 items).
|
|
17
|
+
*
|
|
18
|
+
* State-machine compliance (DESKWORK-STATE-MACHINE.md):
|
|
19
|
+
* - Commandment II: verbs are universal. Approve/Iterate/Cancel are
|
|
20
|
+
* rendered unconditionally inside the Actions slot. The shortform
|
|
21
|
+
* surface header (shortform-review.ts:1-18) explicitly defers the
|
|
22
|
+
* legacy `DraftWorkflowState` migration; for this step we surface
|
|
23
|
+
* the three universal verbs and trust the client clipboard handlers
|
|
24
|
+
* to compose the right slash command from the workflow context.
|
|
25
|
+
* - Commandment III: no review-state surfacing. No "IN REVIEW" /
|
|
26
|
+
* "ITERATING" / "APPROVED" pills. No `.er-stamp`. No
|
|
27
|
+
* `.er-pending-state` markup.
|
|
28
|
+
* - Commandment IV/V/VII: clipboard-copy is the only action. The
|
|
29
|
+
* three buttons carry `data-action="approve|iterate|cancel"`; the
|
|
30
|
+
* existing client handlers in `editorial-review-client.ts` wire
|
|
31
|
+
* them to clipboard-only handlers (post-G.3 refactor).
|
|
32
|
+
* - G.4 (issue #260): the destructive verb is `cancel`, NOT `reject`.
|
|
33
|
+
* The state machine has no `reject` verb.
|
|
34
|
+
*/
|
|
35
|
+
import { html, unsafe, escapeHtml } from "./html.js";
|
|
36
|
+
/**
|
|
37
|
+
* Build the shortform review bar's contextual cell list.
|
|
38
|
+
*
|
|
39
|
+
* Cell ordering (when present): TOC → Versions → Actions. The Actions
|
|
40
|
+
* cell is always last and always present; the bar is never empty.
|
|
41
|
+
*
|
|
42
|
+
* Conditional-omission rules:
|
|
43
|
+
* - TOC cell: omitted when fewer than 2 heading entries exist.
|
|
44
|
+
* Shortform drafts (social-platform copy) are often headingless;
|
|
45
|
+
* surfacing an empty TOC adds noise without value per the
|
|
46
|
+
* "structure over scrolling" principle.
|
|
47
|
+
* - Versions cell: omitted when only one revision exists. With one
|
|
48
|
+
* revision there is no history to navigate.
|
|
49
|
+
*/
|
|
50
|
+
export function getShortformBarCells(opts) {
|
|
51
|
+
const cells = [];
|
|
52
|
+
if (opts.tocEntries.length >= 2) {
|
|
53
|
+
cells.push({
|
|
54
|
+
glyph: '§',
|
|
55
|
+
label: `TOC · ${opts.tocEntries.length}`,
|
|
56
|
+
mode: 'review',
|
|
57
|
+
action: { kind: 'sheet', name: 'toc' },
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (opts.versions.length >= 2) {
|
|
61
|
+
cells.push({
|
|
62
|
+
glyph: '№',
|
|
63
|
+
label: `Versions · ${opts.versions.length}`,
|
|
64
|
+
mode: 'review',
|
|
65
|
+
action: { kind: 'sheet', name: 'versions' },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
cells.push({
|
|
69
|
+
glyph: '⊕',
|
|
70
|
+
label: 'Actions',
|
|
71
|
+
mode: 'review',
|
|
72
|
+
action: { kind: 'sheet', name: 'actions' },
|
|
73
|
+
});
|
|
74
|
+
return cells;
|
|
75
|
+
}
|
|
76
|
+
function renderTocSlotBody(tocEntries) {
|
|
77
|
+
if (tocEntries.length === 0)
|
|
78
|
+
return '';
|
|
79
|
+
const items = tocEntries
|
|
80
|
+
.map((entry) => {
|
|
81
|
+
const depthClass = `er-mobile-toc-item er-mobile-toc-item--h${entry.depth}`;
|
|
82
|
+
return `<li class="${depthClass}"><a href="#${escapeHtml(entry.id)}">${escapeHtml(entry.text)}</a></li>`;
|
|
83
|
+
})
|
|
84
|
+
.join('');
|
|
85
|
+
return `<ul class="er-mobile-toc-list">${items}</ul>`;
|
|
86
|
+
}
|
|
87
|
+
function renderVersionsSlotBody(versions, currentVersion) {
|
|
88
|
+
if (versions.length === 0)
|
|
89
|
+
return '';
|
|
90
|
+
const items = versions
|
|
91
|
+
.map((v) => {
|
|
92
|
+
const isActive = v.version === currentVersion.version;
|
|
93
|
+
const cls = isActive ? ' class="active"' : '';
|
|
94
|
+
return `<li class="er-mobile-versions-item"><a href="?v=${v.version}"${cls}>v${v.version}</a></li>`;
|
|
95
|
+
})
|
|
96
|
+
.join('');
|
|
97
|
+
return `<ul class="er-mobile-versions-list">${items}</ul>`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The Actions slot renders the three universal verbs unconditionally
|
|
101
|
+
* per Commandment II. Per Commandment VII (and THESIS Cons. 2), each
|
|
102
|
+
* button is a clipboard-copy trigger handled by the existing
|
|
103
|
+
* `editorial-review-client.ts` `[data-action]` listeners — the markup
|
|
104
|
+
* here carries no copy-target or state mutation logic; the client
|
|
105
|
+
* composes the slash command from the embedded workflow state.
|
|
106
|
+
*
|
|
107
|
+
* G.4: `data-action="cancel"`, NOT `reject` (the state machine has
|
|
108
|
+
* no `reject` verb; this matches issue #260's resolution shape).
|
|
109
|
+
*/
|
|
110
|
+
function renderActionsSlotBody() {
|
|
111
|
+
return [
|
|
112
|
+
'<div class="er-mobile-actions">',
|
|
113
|
+
' <button class="er-btn er-btn-primary er-btn-approve" data-action="approve" type="button">Approve</button>',
|
|
114
|
+
' <button class="er-btn" data-action="iterate" type="button">Iterate</button>',
|
|
115
|
+
' <button class="er-btn er-btn-cancel" data-action="cancel" type="button">Cancel</button>',
|
|
116
|
+
'</div>',
|
|
117
|
+
].join('\n');
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Render the shortform mobile sheet host with the three named slots
|
|
121
|
+
* (toc / versions / actions). Each slot body is server-rendered so
|
|
122
|
+
* the client doesn't need to clone DOM from elsewhere on the page —
|
|
123
|
+
* the slot is self-contained.
|
|
124
|
+
*
|
|
125
|
+
* The sheet host is always rendered (matches the entry-review pattern
|
|
126
|
+
* where the host is present and the client toggles `hidden` on
|
|
127
|
+
* dispatch). Individual slots are hidden until the corresponding bar
|
|
128
|
+
* cell opens them via the shared `sheet-controller` primitive.
|
|
129
|
+
*/
|
|
130
|
+
export function renderShortformMobileSheet(opts) {
|
|
131
|
+
const tocBody = renderTocSlotBody(opts.tocEntries);
|
|
132
|
+
const versionsBody = renderVersionsSlotBody(opts.versions, opts.currentVersion);
|
|
133
|
+
const actionsBody = renderActionsSlotBody();
|
|
134
|
+
return unsafe(html `
|
|
135
|
+
<section
|
|
136
|
+
class="er-mobile-sheet"
|
|
137
|
+
id="er-mobile-sheet"
|
|
138
|
+
data-mobile-sheet-host
|
|
139
|
+
hidden
|
|
140
|
+
aria-label="Surface sheet"
|
|
141
|
+
role="dialog"
|
|
142
|
+
aria-modal="false"
|
|
143
|
+
>
|
|
144
|
+
<button class="er-mobile-sheet-handle" data-mobile-sheet-handle type="button" aria-label="Drag to dismiss the sheet">
|
|
145
|
+
<span class="er-mobile-sheet-handle-bar" aria-hidden="true"></span>
|
|
146
|
+
</button>
|
|
147
|
+
<header class="er-mobile-sheet-head">
|
|
148
|
+
<span class="er-mobile-sheet-kicker" data-mobile-sheet-kicker></span>
|
|
149
|
+
<span class="er-mobile-sheet-meta" data-mobile-sheet-meta></span>
|
|
150
|
+
<button class="er-mobile-sheet-close" data-mobile-sheet-close type="button" aria-label="Close sheet">×</button>
|
|
151
|
+
</header>
|
|
152
|
+
<div class="er-mobile-sheet-body" data-mobile-sheet-body>
|
|
153
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="toc" hidden>${unsafe(tocBody)}</div>
|
|
154
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="versions" hidden>${unsafe(versionsBody)}</div>
|
|
155
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="actions" hidden>${unsafe(actionsBody)}</div>
|
|
156
|
+
</div>
|
|
157
|
+
</section>`);
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=shortform-review-mobile-sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shortform-review-mobile-sheet.js","sourceRoot":"","sources":["../../src/pages/shortform-review-mobile-sheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortform-review-specific mobile sheet host + bar cell composition.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `entry-review/mobile-sheet.ts` for the shortform review
|
|
5
|
+
* surface. The mobile-bar primitive (`../mobile-bar.ts`) is universal;
|
|
6
|
+
* each surface composes its `Cell[]` and the corresponding slot host
|
|
7
|
+
* here.
|
|
8
|
+
*
|
|
9
|
+
* Design contract (DESIGN-STANDARDS.md § Universal bar contract,
|
|
10
|
+
* settled 2026-05-13):
|
|
11
|
+
* - One bar primitive, one shape. The per-surface design variable
|
|
12
|
+
* is the cells, not the chrome.
|
|
13
|
+
* - 1-6 contextual cells. The Actions cell is unconditional so the
|
|
14
|
+
* bar is never empty (renderMobileBar throws on empty cells).
|
|
15
|
+
* - The TOC and Versions cells are conditional (hidden when their
|
|
16
|
+
* content has fewer than 2 items).
|
|
17
|
+
*
|
|
18
|
+
* State-machine compliance (DESKWORK-STATE-MACHINE.md):
|
|
19
|
+
* - Commandment II: verbs are universal. Approve/Iterate/Cancel are
|
|
20
|
+
* rendered unconditionally inside the Actions slot. The shortform
|
|
21
|
+
* surface header (shortform-review.ts:1-18) explicitly defers the
|
|
22
|
+
* legacy `DraftWorkflowState` migration; for this step we surface
|
|
23
|
+
* the three universal verbs and trust the client clipboard handlers
|
|
24
|
+
* to compose the right slash command from the workflow context.
|
|
25
|
+
* - Commandment III: no review-state surfacing. No "IN REVIEW" /
|
|
26
|
+
* "ITERATING" / "APPROVED" pills. No `.er-stamp`. No
|
|
27
|
+
* `.er-pending-state` markup.
|
|
28
|
+
* - Commandment IV/V/VII: clipboard-copy is the only action. The
|
|
29
|
+
* three buttons carry `data-action="approve|iterate|cancel"`; the
|
|
30
|
+
* existing client handlers in `editorial-review-client.ts` wire
|
|
31
|
+
* them to clipboard-only handlers (post-G.3 refactor).
|
|
32
|
+
* - G.4 (issue #260): the destructive verb is `cancel`, NOT `reject`.
|
|
33
|
+
* The state machine has no `reject` verb.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { TocEntry } from '@deskwork/core/review/toc';
|
|
37
|
+
import type {
|
|
38
|
+
DraftVersion,
|
|
39
|
+
DraftWorkflowItem,
|
|
40
|
+
} from '@deskwork/core/review/types';
|
|
41
|
+
import { html, unsafe, escapeHtml, type RawHtml } from './html.ts';
|
|
42
|
+
import type { Cell } from './mobile-bar.ts';
|
|
43
|
+
|
|
44
|
+
export interface ShortformBarCellOptions {
|
|
45
|
+
readonly tocEntries: readonly TocEntry[];
|
|
46
|
+
readonly versions: readonly DraftVersion[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Build the shortform review bar's contextual cell list.
|
|
51
|
+
*
|
|
52
|
+
* Cell ordering (when present): TOC → Versions → Actions. The Actions
|
|
53
|
+
* cell is always last and always present; the bar is never empty.
|
|
54
|
+
*
|
|
55
|
+
* Conditional-omission rules:
|
|
56
|
+
* - TOC cell: omitted when fewer than 2 heading entries exist.
|
|
57
|
+
* Shortform drafts (social-platform copy) are often headingless;
|
|
58
|
+
* surfacing an empty TOC adds noise without value per the
|
|
59
|
+
* "structure over scrolling" principle.
|
|
60
|
+
* - Versions cell: omitted when only one revision exists. With one
|
|
61
|
+
* revision there is no history to navigate.
|
|
62
|
+
*/
|
|
63
|
+
export function getShortformBarCells(opts: ShortformBarCellOptions): readonly Cell[] {
|
|
64
|
+
const cells: Cell[] = [];
|
|
65
|
+
if (opts.tocEntries.length >= 2) {
|
|
66
|
+
cells.push({
|
|
67
|
+
glyph: '§',
|
|
68
|
+
label: `TOC · ${opts.tocEntries.length}`,
|
|
69
|
+
mode: 'review',
|
|
70
|
+
action: { kind: 'sheet', name: 'toc' },
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (opts.versions.length >= 2) {
|
|
74
|
+
cells.push({
|
|
75
|
+
glyph: '№',
|
|
76
|
+
label: `Versions · ${opts.versions.length}`,
|
|
77
|
+
mode: 'review',
|
|
78
|
+
action: { kind: 'sheet', name: 'versions' },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
cells.push({
|
|
82
|
+
glyph: '⊕',
|
|
83
|
+
label: 'Actions',
|
|
84
|
+
mode: 'review',
|
|
85
|
+
action: { kind: 'sheet', name: 'actions' },
|
|
86
|
+
});
|
|
87
|
+
return cells;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface ShortformMobileSheetOptions {
|
|
91
|
+
readonly tocEntries: readonly TocEntry[];
|
|
92
|
+
readonly versions: readonly DraftVersion[];
|
|
93
|
+
readonly workflow: DraftWorkflowItem;
|
|
94
|
+
readonly currentVersion: DraftVersion;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function renderTocSlotBody(tocEntries: readonly TocEntry[]): string {
|
|
98
|
+
if (tocEntries.length === 0) return '';
|
|
99
|
+
const items = tocEntries
|
|
100
|
+
.map((entry) => {
|
|
101
|
+
const depthClass = `er-mobile-toc-item er-mobile-toc-item--h${entry.depth}`;
|
|
102
|
+
return `<li class="${depthClass}"><a href="#${escapeHtml(entry.id)}">${escapeHtml(entry.text)}</a></li>`;
|
|
103
|
+
})
|
|
104
|
+
.join('');
|
|
105
|
+
return `<ul class="er-mobile-toc-list">${items}</ul>`;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function renderVersionsSlotBody(
|
|
109
|
+
versions: readonly DraftVersion[],
|
|
110
|
+
currentVersion: DraftVersion,
|
|
111
|
+
): string {
|
|
112
|
+
if (versions.length === 0) return '';
|
|
113
|
+
const items = versions
|
|
114
|
+
.map((v) => {
|
|
115
|
+
const isActive = v.version === currentVersion.version;
|
|
116
|
+
const cls = isActive ? ' class="active"' : '';
|
|
117
|
+
return `<li class="er-mobile-versions-item"><a href="?v=${v.version}"${cls}>v${v.version}</a></li>`;
|
|
118
|
+
})
|
|
119
|
+
.join('');
|
|
120
|
+
return `<ul class="er-mobile-versions-list">${items}</ul>`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* The Actions slot renders the three universal verbs unconditionally
|
|
125
|
+
* per Commandment II. Per Commandment VII (and THESIS Cons. 2), each
|
|
126
|
+
* button is a clipboard-copy trigger handled by the existing
|
|
127
|
+
* `editorial-review-client.ts` `[data-action]` listeners — the markup
|
|
128
|
+
* here carries no copy-target or state mutation logic; the client
|
|
129
|
+
* composes the slash command from the embedded workflow state.
|
|
130
|
+
*
|
|
131
|
+
* G.4: `data-action="cancel"`, NOT `reject` (the state machine has
|
|
132
|
+
* no `reject` verb; this matches issue #260's resolution shape).
|
|
133
|
+
*/
|
|
134
|
+
function renderActionsSlotBody(): string {
|
|
135
|
+
return [
|
|
136
|
+
'<div class="er-mobile-actions">',
|
|
137
|
+
' <button class="er-btn er-btn-primary er-btn-approve" data-action="approve" type="button">Approve</button>',
|
|
138
|
+
' <button class="er-btn" data-action="iterate" type="button">Iterate</button>',
|
|
139
|
+
' <button class="er-btn er-btn-cancel" data-action="cancel" type="button">Cancel</button>',
|
|
140
|
+
'</div>',
|
|
141
|
+
].join('\n');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Render the shortform mobile sheet host with the three named slots
|
|
146
|
+
* (toc / versions / actions). Each slot body is server-rendered so
|
|
147
|
+
* the client doesn't need to clone DOM from elsewhere on the page —
|
|
148
|
+
* the slot is self-contained.
|
|
149
|
+
*
|
|
150
|
+
* The sheet host is always rendered (matches the entry-review pattern
|
|
151
|
+
* where the host is present and the client toggles `hidden` on
|
|
152
|
+
* dispatch). Individual slots are hidden until the corresponding bar
|
|
153
|
+
* cell opens them via the shared `sheet-controller` primitive.
|
|
154
|
+
*/
|
|
155
|
+
export function renderShortformMobileSheet(
|
|
156
|
+
opts: ShortformMobileSheetOptions,
|
|
157
|
+
): RawHtml {
|
|
158
|
+
const tocBody = renderTocSlotBody(opts.tocEntries);
|
|
159
|
+
const versionsBody = renderVersionsSlotBody(opts.versions, opts.currentVersion);
|
|
160
|
+
const actionsBody = renderActionsSlotBody();
|
|
161
|
+
return unsafe(html`
|
|
162
|
+
<section
|
|
163
|
+
class="er-mobile-sheet"
|
|
164
|
+
id="er-mobile-sheet"
|
|
165
|
+
data-mobile-sheet-host
|
|
166
|
+
hidden
|
|
167
|
+
aria-label="Surface sheet"
|
|
168
|
+
role="dialog"
|
|
169
|
+
aria-modal="false"
|
|
170
|
+
>
|
|
171
|
+
<button class="er-mobile-sheet-handle" data-mobile-sheet-handle type="button" aria-label="Drag to dismiss the sheet">
|
|
172
|
+
<span class="er-mobile-sheet-handle-bar" aria-hidden="true"></span>
|
|
173
|
+
</button>
|
|
174
|
+
<header class="er-mobile-sheet-head">
|
|
175
|
+
<span class="er-mobile-sheet-kicker" data-mobile-sheet-kicker></span>
|
|
176
|
+
<span class="er-mobile-sheet-meta" data-mobile-sheet-meta></span>
|
|
177
|
+
<button class="er-mobile-sheet-close" data-mobile-sheet-close type="button" aria-label="Close sheet">×</button>
|
|
178
|
+
</header>
|
|
179
|
+
<div class="er-mobile-sheet-body" data-mobile-sheet-body>
|
|
180
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="toc" hidden>${unsafe(tocBody)}</div>
|
|
181
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="versions" hidden>${unsafe(versionsBody)}</div>
|
|
182
|
+
<div class="er-mobile-sheet-slot" data-mobile-sheet-slot="actions" hidden>${unsafe(actionsBody)}</div>
|
|
183
|
+
</div>
|
|
184
|
+
</section>`);
|
|
185
|
+
}
|
|
@@ -15,6 +15,24 @@
|
|
|
15
15
|
*
|
|
16
16
|
* Workflow-keyed wording in this file is documenting that deliberate
|
|
17
17
|
* deferral; do not flag in audits.
|
|
18
|
+
*
|
|
19
|
+
* Step 2.2.10 (v7 universal chrome + state-machine compliance):
|
|
20
|
+
* - Server-side: er-strip / er-stamp / er-pending-state / shortcut
|
|
21
|
+
* overlay / state-branched control rendering all REMOVED. The
|
|
22
|
+
* universal `renderMobileBar` primitive + a shortform-specific
|
|
23
|
+
* sheet host (`./shortform-review-mobile-sheet.ts`) replace them.
|
|
24
|
+
* - Per DESIGN-STANDARDS.md § Universal bar contract: this surface
|
|
25
|
+
* composes its `Cell[]` mechanically (TOC / Versions / Actions)
|
|
26
|
+
* and passes it to `renderMobileBar`. No bespoke chrome shape.
|
|
27
|
+
* - Per DESKWORK-STATE-MACHINE.md Commandment III: no review-state
|
|
28
|
+
* labels on the page (the stamp + pending pills were the
|
|
29
|
+
* violations).
|
|
30
|
+
* - The desktop edit-mode panes (`renderEditPanes`) stay — they're
|
|
31
|
+
* gated by the existing `data-edit-mode` body attribute and the
|
|
32
|
+
* Edit toolbar is still part of the desktop chrome. Mobile edit
|
|
33
|
+
* entry-point is deferred to a future task (the workplan keeps
|
|
34
|
+
* the broader shortform state-machine migration explicitly out
|
|
35
|
+
* of scope for this step).
|
|
18
36
|
*/
|
|
19
37
|
import type { StudioContext } from '../routes/api.ts';
|
|
20
38
|
interface ShortformReviewQuery {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shortform-review.d.ts","sourceRoot":"","sources":["../../src/pages/shortform-review.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"shortform-review.d.ts","sourceRoot":"","sources":["../../src/pages/shortform-review.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAYH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAYtD,UAAU,oBAAoB;IAC5B,wDAAwD;IACxD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AA2FD;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,GAAG,EAAE,aAAa,EAClB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA0GjB"}
|