@deskwork/studio 0.17.1 → 0.19.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.
Files changed (51) hide show
  1. package/dist/pages/dashboard/affordances.d.ts +19 -24
  2. package/dist/pages/dashboard/affordances.d.ts.map +1 -1
  3. package/dist/pages/dashboard/affordances.js +52 -41
  4. package/dist/pages/dashboard/affordances.js.map +1 -1
  5. package/dist/pages/dashboard/affordances.ts +56 -45
  6. package/dist/pages/dashboard/header.d.ts +9 -3
  7. package/dist/pages/dashboard/header.d.ts.map +1 -1
  8. package/dist/pages/dashboard/header.js +10 -30
  9. package/dist/pages/dashboard/header.js.map +1 -1
  10. package/dist/pages/dashboard/header.ts +10 -32
  11. package/dist/pages/dashboard/section.d.ts +42 -15
  12. package/dist/pages/dashboard/section.d.ts.map +1 -1
  13. package/dist/pages/dashboard/section.js +118 -49
  14. package/dist/pages/dashboard/section.js.map +1 -1
  15. package/dist/pages/dashboard/section.ts +120 -53
  16. package/dist/pages/dashboard.d.ts +23 -17
  17. package/dist/pages/dashboard.d.ts.map +1 -1
  18. package/dist/pages/dashboard.js +105 -25
  19. package/dist/pages/dashboard.js.map +1 -1
  20. package/dist/pages/dashboard.ts +107 -26
  21. package/dist/pages/entry-review/decision-strip.d.ts.map +1 -1
  22. package/dist/pages/entry-review/decision-strip.js +4 -0
  23. package/dist/pages/entry-review/decision-strip.js.map +1 -1
  24. package/dist/pages/entry-review/edit-toolbar.d.ts +1 -1
  25. package/dist/pages/entry-review/edit-toolbar.d.ts.map +1 -1
  26. package/dist/pages/entry-review/edit-toolbar.js +9 -1
  27. package/dist/pages/entry-review/edit-toolbar.js.map +1 -1
  28. package/dist/pages/entry-review/index.d.ts.map +1 -1
  29. package/dist/pages/entry-review/index.js +14 -4
  30. package/dist/pages/entry-review/index.js.map +1 -1
  31. package/dist/pages/entry-review/mobile-bar.d.ts +62 -0
  32. package/dist/pages/entry-review/mobile-bar.d.ts.map +1 -0
  33. package/dist/pages/entry-review/mobile-bar.js +155 -0
  34. package/dist/pages/entry-review/mobile-bar.js.map +1 -0
  35. package/dist/pages/entry-review/outline-drawer.d.ts +17 -7
  36. package/dist/pages/entry-review/outline-drawer.d.ts.map +1 -1
  37. package/dist/pages/entry-review/outline-drawer.js +58 -14
  38. package/dist/pages/entry-review/outline-drawer.js.map +1 -1
  39. package/dist/pages/help.js +1 -1
  40. package/dist/pages/help.ts +1 -1
  41. package/dist/pages/index.d.ts +8 -6
  42. package/dist/pages/index.d.ts.map +1 -1
  43. package/dist/pages/index.js +16 -14
  44. package/dist/pages/index.js.map +1 -1
  45. package/dist/pages/index.ts +16 -14
  46. package/dist/pages/layout.js +1 -1
  47. package/dist/pages/layout.ts +1 -1
  48. package/dist/server.d.ts.map +1 -1
  49. package/dist/server.js +12 -1
  50. package/dist/server.js.map +1 -1
  51. package/package.json +2 -2
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Mobile bottom-bar + sheet host for the entry-keyed review surface.
3
+ *
4
+ * Renders a 3-tab bottom bar and a sheet host that slides up from the
5
+ * viewport bottom. Visible only at <48rem (phone widths) — see
6
+ * editorial-review.css. Above that the bar and sheet are display:none
7
+ * and the desktop layout (in-flow marginalia column, outline-drawer
8
+ * overlay, decision strip in the top strip) carries the surface.
9
+ *
10
+ * Design references:
11
+ * - Review tabs: plugins/deskwork-studio/public/mockups/mobile-1-bottom-sheet.html
12
+ * - Editor tabs: plugins/deskwork-studio/public/mockups/editor-2-press-check-tabbar.html
13
+ *
14
+ * The bar carries SIX tab buttons; CSS shows three or four at a time
15
+ * keyed off `body[data-edit-mode="editing"]`:
16
+ * - Review mode: Outline · Notes · Scrapbook · Actions (4-column grid)
17
+ * - Edit mode: Format · Notes · Save (3-column grid)
18
+ * The Notes tab is shared between modes (review notes the operator
19
+ * leaves carry across into edit). The bar's data-mode attribute is
20
+ * also flipped by the client so additional state-dependent styles
21
+ * (Save dirty glow, etc.) can key off it. The Scrapbook tab uses a
22
+ * grid glyph (▦) and a kraft-tone count badge to distinguish it
23
+ * from the red-pencil Notes badge — folio is "context for the
24
+ * entry," not an action peer of decisions.
25
+ *
26
+ * The sheet has five content slots (outline / notes / actions /
27
+ * scrapbook / format).
28
+ * The client controller (`entry-review/mobile-sheet-bar.ts`) populates
29
+ * each at first open. Slot sources:
30
+ * - outline: clone of `.er-outline-drawer-body`
31
+ * - notes: actual `[data-sidebar-list]` element MOVED in on phone
32
+ * (preserves event listeners; see mobile-sheet-bar.ts)
33
+ * - actions: rendered fresh from the decision verbs
34
+ * - format: the press-check key grid rendered server-side below
35
+ *
36
+ * The Save tab is NOT a sheet — it triggers the existing
37
+ * `[data-action="save-version"]` handler directly (the one allowed
38
+ * file mutation per THESIS Consequence 2).
39
+ */
40
+ import { html, unsafe } from "../html.js";
41
+ export function renderMobileBar() {
42
+ return unsafe(html `
43
+ <nav class="er-mobile-bar" data-mobile-bar aria-label="Surface tabs">
44
+ <button class="er-mobile-tab er-mobile-tab--review" data-mobile-sheet="outline" type="button" aria-controls="er-mobile-sheet" aria-expanded="false">
45
+ <span class="er-mobile-tab-glyph" aria-hidden="true">§</span>
46
+ <span class="er-mobile-tab-label">Outline</span>
47
+ </button>
48
+ <button class="er-mobile-tab er-mobile-tab--edit" data-mobile-sheet="format" type="button" aria-controls="er-mobile-sheet" aria-expanded="false">
49
+ <span class="er-mobile-tab-glyph" aria-hidden="true">¶</span>
50
+ <span class="er-mobile-tab-label">Format</span>
51
+ </button>
52
+ <button class="er-mobile-tab" data-mobile-sheet="notes" type="button" aria-controls="er-mobile-sheet" aria-expanded="false">
53
+ <span class="er-mobile-tab-glyph" aria-hidden="true">✎</span>
54
+ <span class="er-mobile-tab-label">Notes</span>
55
+ <span class="er-mobile-tab-count" data-notes-count hidden>0</span>
56
+ </button>
57
+ <button class="er-mobile-tab er-mobile-tab--review er-mobile-tab--scrapbook" data-mobile-sheet="scrapbook" type="button" aria-controls="er-mobile-sheet" aria-expanded="false">
58
+ <span class="er-mobile-tab-glyph" aria-hidden="true">▦</span>
59
+ <span class="er-mobile-tab-label">Scrapbook</span>
60
+ <span class="er-mobile-tab-count er-mobile-tab-count--kraft" data-scrapbook-count hidden>0</span>
61
+ </button>
62
+ <button class="er-mobile-tab er-mobile-tab--review" data-mobile-sheet="actions" type="button" aria-controls="er-mobile-sheet" aria-expanded="false">
63
+ <span class="er-mobile-tab-glyph" aria-hidden="true">⊕</span>
64
+ <span class="er-mobile-tab-label">Actions</span>
65
+ </button>
66
+ <button class="er-mobile-tab er-mobile-tab--edit er-mobile-tab--save" data-mobile-action="save" type="button">
67
+ <span class="er-mobile-tab-glyph" aria-hidden="true">⊕</span>
68
+ <span class="er-mobile-tab-label">Save</span>
69
+ </button>
70
+ </nav>`);
71
+ }
72
+ function renderFormatGrid() {
73
+ return html `
74
+ <div class="er-fkey-section">Headings</div>
75
+ <div class="er-fkey-grid">
76
+ <button type="button" class="er-fkey er-fkey--h1" data-fkey="h1"><span class="er-fkey-face">H1</span><span class="er-fkey-label">Title</span></button>
77
+ <button type="button" class="er-fkey er-fkey--h2" data-fkey="h2"><span class="er-fkey-face">H2</span><span class="er-fkey-label">Section</span></button>
78
+ <button type="button" class="er-fkey er-fkey--h3" data-fkey="h3"><span class="er-fkey-face">H3</span><span class="er-fkey-label">Sub</span></button>
79
+ <button type="button" class="er-fkey er-fkey--hr" data-fkey="hr"><span class="er-fkey-face">— · — · —</span><span class="er-fkey-label">Rule</span></button>
80
+ </div>
81
+ <div class="er-fkey-section">Inline</div>
82
+ <div class="er-fkey-grid">
83
+ <button type="button" class="er-fkey er-fkey--bold" data-fkey="bold"><span class="er-fkey-face"><strong>B</strong></span><span class="er-fkey-label">Bold</span></button>
84
+ <button type="button" class="er-fkey er-fkey--em" data-fkey="em"><span class="er-fkey-face"><em>I</em></span><span class="er-fkey-label">Italic</span></button>
85
+ <button type="button" class="er-fkey er-fkey--code" data-fkey="code"><span class="er-fkey-face">\` \`</span><span class="er-fkey-label">Code</span></button>
86
+ <button type="button" class="er-fkey er-fkey--link" data-fkey="link"><span class="er-fkey-face">link</span><span class="er-fkey-label">Link</span></button>
87
+ </div>
88
+ <div class="er-fkey-section">Block</div>
89
+ <div class="er-fkey-grid">
90
+ <button type="button" class="er-fkey er-fkey--list" data-fkey="list"><span class="er-fkey-face">— ·<br>— ·</span><span class="er-fkey-label">List</span></button>
91
+ <button type="button" class="er-fkey er-fkey--ol" data-fkey="ol"><span class="er-fkey-face">1·<br>2·</span><span class="er-fkey-label">Numbered</span></button>
92
+ <button type="button" class="er-fkey er-fkey--quote" data-fkey="quote"><span class="er-fkey-face">"</span><span class="er-fkey-label">Quote</span></button>
93
+ <button type="button" class="er-fkey er-fkey--fence" data-fkey="fence"><span class="er-fkey-face">\`\`\`</span><span class="er-fkey-label">Code block</span></button>
94
+ </div>`;
95
+ }
96
+ export function renderMobileSheet() {
97
+ return unsafe(html `
98
+ <section
99
+ class="er-mobile-sheet"
100
+ id="er-mobile-sheet"
101
+ data-mobile-sheet-host
102
+ hidden
103
+ aria-label="Surface sheet"
104
+ role="dialog"
105
+ aria-modal="false"
106
+ >
107
+ <button class="er-mobile-sheet-handle" data-mobile-sheet-handle type="button" aria-label="Drag to dismiss the sheet">
108
+ <span class="er-mobile-sheet-handle-bar" aria-hidden="true"></span>
109
+ </button>
110
+ <header class="er-mobile-sheet-head">
111
+ <span class="er-mobile-sheet-kicker" data-mobile-sheet-kicker></span>
112
+ <span class="er-mobile-sheet-meta" data-mobile-sheet-meta></span>
113
+ <button class="er-mobile-sheet-close" data-mobile-sheet-close type="button" aria-label="Close sheet">×</button>
114
+ </header>
115
+ <div class="er-mobile-sheet-body" data-mobile-sheet-body>
116
+ <div class="er-mobile-sheet-slot" data-mobile-sheet-slot="outline" hidden></div>
117
+ <div class="er-mobile-sheet-slot" data-mobile-sheet-slot="notes" hidden></div>
118
+ <div class="er-mobile-sheet-slot" data-mobile-sheet-slot="actions" hidden></div>
119
+ <div class="er-mobile-sheet-slot er-mobile-sheet-slot--scrapbook" data-mobile-sheet-slot="scrapbook" hidden></div>
120
+ <div class="er-mobile-sheet-slot er-mobile-sheet-slot--format" data-mobile-sheet-slot="format" hidden>${unsafe(renderFormatGrid())}</div>
121
+ </div>
122
+ </section>`);
123
+ }
124
+ /**
125
+ * Phone-only Source/Preview pill rendered into the top strip when in
126
+ * edit mode. Uses the same `data-edit-view` attribute as the desktop
127
+ * edit toolbar so `editModeBtns` (queried via that attribute in
128
+ * entry-review-client.ts) auto-binds clicks. CSS reveals it only on
129
+ * phone + edit mode; the desktop edit toolbar is hidden in that
130
+ * combination.
131
+ */
132
+ export function renderStripModeSegment() {
133
+ return unsafe(html `
134
+ <span class="er-strip-mode-mobile" data-strip-mode-mobile aria-hidden="true">
135
+ <button type="button" class="er-strip-mode-btn" data-edit-view="source" aria-pressed="true">Source</button>
136
+ <button type="button" class="er-strip-mode-btn" data-edit-view="preview" aria-pressed="false">Preview</button>
137
+ </span>`);
138
+ }
139
+ /**
140
+ * Phone-only "✕ Done" exit affordance in the strip. Visible only when
141
+ * editing on phone (CSS-gated). Click dispatches into the existing
142
+ * toggle-edit handler — preserves the confirmDiscard prompt when the
143
+ * buffer is dirty, immediate exit when clean. Sits alongside the
144
+ * existing back-link (which continues to navigate home regardless of
145
+ * mode) so the operator always has both "leave editor" and "leave
146
+ * page" affordances available.
147
+ */
148
+ export function renderStripEditExit() {
149
+ return unsafe(html `
150
+ <button type="button" class="er-strip-edit-done" data-strip-edit-done aria-label="Exit editor">
151
+ <span class="er-strip-edit-done-glyph" aria-hidden="true">✕</span>
152
+ <span class="er-strip-edit-done-label">Done</span>
153
+ </button>`);
154
+ }
155
+ //# sourceMappingURL=mobile-bar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile-bar.js","sourceRoot":"","sources":["../../../src/pages/entry-review/mobile-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAExD,MAAM,UAAU,eAAe;IAC7B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;WA4BT,CAAC,CAAC;AACb,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;WAqBF,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;;;;;;;;;;;;;;;;;gHAuB4F,MAAM,CAAC,gBAAgB,EAAE,CAAC;;eAE3H,CAAC,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,MAAM,CAAC,IAAI,CAAA;;;;YAIR,CAAC,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,IAAI,CAAA;;;;cAIN,CAAC,CAAC;AAChB,CAAC"}
@@ -1,12 +1,22 @@
1
1
  /**
2
- * Outline drawer for the entry-keyed press-check surface (Phase 34a — T9).
2
+ * Outline + TOC drawer for the entry-keyed press-check surface.
3
3
  *
4
- * Relocated from `pages/review.ts:renderOutlineDrawer`. Conditional render
5
- * when the entry's body markdown carries a `## Outline` section (extracted
6
- * via `splitOutline`). The pull-tab on the left edge mirrors the marginalia
7
- * tab pattern on the right edge; the drawer is read-only and links to
8
- * `/deskwork:iterate --kind outline` for editing.
4
+ * Two stacked sections inside the same drawer:
5
+ * 1. Curated outline (#169-pre, T9). Conditional on the entry's body
6
+ * markdown carrying a `## Outline` section (extracted via
7
+ * `splitOutline`). When present, this is the operator's hand-
8
+ * authored briefing sheet read-only here; edit via
9
+ * `/deskwork:iterate --kind outline`.
10
+ * 2. Table of contents (#244). Auto-extracted from the rendered
11
+ * body's h2/h3/h4 headings (each carries a slugified `id` from
12
+ * rehype-slug). Always visible when there are 2+ entries; clicks
13
+ * jump to the heading via native `<a href="#id">` smooth-scroll.
14
+ *
15
+ * The pull-tab on the left edge surfaces whenever EITHER section has
16
+ * content. The drawer is `position: fixed` so it never scrolls out
17
+ * of view.
9
18
  */
10
19
  import { type RawHtml } from '../html.ts';
11
- export declare function renderOutlineDrawer(outlineHtml: string): RawHtml;
20
+ import type { TocEntry } from '@deskwork/core/review/toc';
21
+ export declare function renderOutlineDrawer(outlineHtml: string, tocEntries?: readonly TocEntry[]): RawHtml;
12
22
  //# sourceMappingURL=outline-drawer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"outline-drawer.d.ts","sourceRoot":"","sources":["../../../src/pages/entry-review/outline-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAgBhE"}
1
+ {"version":3,"file":"outline-drawer.d.ts","sourceRoot":"","sources":["../../../src/pages/entry-review/outline-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,UAAU,GAAE,SAAS,QAAQ,EAAO,GACnC,OAAO,CAiCT"}
@@ -1,28 +1,72 @@
1
1
  /**
2
- * Outline drawer for the entry-keyed press-check surface (Phase 34a — T9).
2
+ * Outline + TOC drawer for the entry-keyed press-check surface.
3
3
  *
4
- * Relocated from `pages/review.ts:renderOutlineDrawer`. Conditional render
5
- * when the entry's body markdown carries a `## Outline` section (extracted
6
- * via `splitOutline`). The pull-tab on the left edge mirrors the marginalia
7
- * tab pattern on the right edge; the drawer is read-only and links to
8
- * `/deskwork:iterate --kind outline` for editing.
4
+ * Two stacked sections inside the same drawer:
5
+ * 1. Curated outline (#169-pre, T9). Conditional on the entry's body
6
+ * markdown carrying a `## Outline` section (extracted via
7
+ * `splitOutline`). When present, this is the operator's hand-
8
+ * authored briefing sheet read-only here; edit via
9
+ * `/deskwork:iterate --kind outline`.
10
+ * 2. Table of contents (#244). Auto-extracted from the rendered
11
+ * body's h2/h3/h4 headings (each carries a slugified `id` from
12
+ * rehype-slug). Always visible when there are 2+ entries; clicks
13
+ * jump to the heading via native `<a href="#id">` smooth-scroll.
14
+ *
15
+ * The pull-tab on the left edge surfaces whenever EITHER section has
16
+ * content. The drawer is `position: fixed` so it never scrolls out
17
+ * of view.
9
18
  */
10
19
  import { html, unsafe } from "../html.js";
11
- export function renderOutlineDrawer(outlineHtml) {
12
- const hidden = outlineHtml ? '' : ' hidden';
20
+ export function renderOutlineDrawer(outlineHtml, tocEntries = []) {
21
+ const hasOutline = outlineHtml.length > 0;
22
+ const hasToc = tocEntries.length >= 2;
23
+ const tabHidden = hasOutline || hasToc ? '' : ' hidden';
24
+ // Drawer kicker label: prefer "Outline" when there's a curated
25
+ // outline (the briefing-sheet heritage); otherwise "Contents" since
26
+ // the auto-TOC is the dominant content. Both sections may render
27
+ // simultaneously when the entry has both.
28
+ const kicker = hasOutline ? 'Briefing sheet' : 'Contents';
13
29
  return unsafe(html `
14
- <button class="er-outline-tab" data-outline-tab type="button" aria-label="Show outline"${unsafe(hidden)}>
30
+ <button class="er-outline-tab" data-outline-tab type="button" aria-label="Show outline / contents"${unsafe(tabHidden)}>
15
31
  <span class="er-outline-tab-label">Outline</span>
16
32
  </button>
17
- <aside class="er-outline-drawer" data-outline-drawer aria-label="Outline reference" hidden>
33
+ <aside class="er-outline-drawer" data-outline-drawer aria-label="Outline + table of contents" hidden>
18
34
  <header class="er-outline-drawer-head">
19
- <span class="er-outline-drawer-kicker">Briefing sheet</span>
20
- <button type="button" class="er-outline-drawer-close" data-outline-close aria-label="Close outline (O or Esc)">×</button>
35
+ <button type="button" class="er-outline-drawer-stow" data-outline-close aria-label="Hide outline (O or Esc)" title="Hide outline (O or Esc)">
36
+ <span aria-hidden="true">‹</span>
37
+ </button>
38
+ <span class="er-outline-drawer-kicker">${kicker}</span>
21
39
  </header>
22
- <div class="er-outline-drawer-body" data-outline-drawer-body>${unsafe(outlineHtml)}</div>
40
+ <div class="er-outline-drawer-body" data-outline-drawer-body>
41
+ ${unsafe(hasOutline ? outlineHtml : '')}
42
+ ${unsafe(hasOutline && hasToc ? '<hr class="er-outline-drawer-rule" />' : '')}
43
+ ${unsafe(hasToc ? renderTocList(tocEntries) : '')}
44
+ </div>
23
45
  <footer class="er-outline-drawer-foot">
24
- <span>Read-only · edit via <code>/deskwork:iterate --kind outline</code></span>
46
+ ${unsafe(hasOutline
47
+ ? '<span>Read-only · edit via <code>/deskwork:iterate --kind outline</code></span>'
48
+ : '<span>Auto-extracted from headings · jump-link to navigate</span>')}
25
49
  </footer>
26
50
  </aside>`);
27
51
  }
52
+ /**
53
+ * Render the auto-TOC as an indented list of anchor links. Depth maps
54
+ * directly to nesting level: depth-2 entries are top-level, depth-3
55
+ * entries indent once, depth-4 entries indent twice. The flat HTML
56
+ * shape is easier to style than nested <ul>s and reads correctly with
57
+ * a screen reader as long as the depth class carries an aria
58
+ * attribute (set in CSS via `aria-level`).
59
+ */
60
+ function renderTocList(entries) {
61
+ const items = entries
62
+ .map((e) => html `
63
+ <li class="er-toc-item er-toc-item--d${e.depth}" data-toc-target="${e.id}">
64
+ <a class="er-toc-link" href="#${e.id}" data-toc-link>${e.text}</a>
65
+ </li>`)
66
+ .join('');
67
+ return html `
68
+ <nav class="er-toc" aria-label="Table of contents">
69
+ <ul class="er-toc-list">${unsafe(items)}</ul>
70
+ </nav>`;
71
+ }
28
72
  //# sourceMappingURL=outline-drawer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"outline-drawer.js","sourceRoot":"","sources":["../../../src/pages/entry-review/outline-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAExD,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5C,OAAO,MAAM,CAAC,IAAI,CAAA;6FACyE,MAAM,CAAC,MAAM,CAAC;;;;;;;;qEAQtC,MAAM,CAAC,WAAW,CAAC;;;;aAI3E,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"outline-drawer.js","sourceRoot":"","sources":["../../../src/pages/entry-review/outline-drawer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAGxD,MAAM,UAAU,mBAAmB,CACjC,WAAmB,EACnB,aAAkC,EAAE;IAEpC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAExD,+DAA+D;IAC/D,oEAAoE;IACpE,iEAAiE;IACjE,0CAA0C;IAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC;IAE1D,OAAO,MAAM,CAAC,IAAI,CAAA;wGACoF,MAAM,CAAC,SAAS,CAAC;;;;;;;;iDAQxE,MAAM;;;UAG7C,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;UACrC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC,EAAE,CAAC;UAC3E,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;;;UAG/C,MAAM,CAAC,UAAU;QACjB,CAAC,CAAC,iFAAiF;QACnF,CAAC,CAAC,mEAAmE,CAAC;;aAEnE,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,OAA4B;IACjD,MAAM,KAAK,GAAG,OAAO;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;6CACyB,CAAC,CAAC,KAAK,sBAAsB,CAAC,CAAC,EAAE;wCACtC,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,IAAI;YACzD,CAAC;SACR,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,IAAI,CAAA;;gCAEmB,MAAM,CAAC,KAAK,CAAC;WAClC,CAAC;AACZ,CAAC"}
@@ -241,7 +241,7 @@ function renderStudioSection() {
241
241
  <div class="eh-panel">
242
242
  <p class="eh-panel-head">Secondary surfaces</p>
243
243
  <h4>Entry review</h4>
244
- <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
244
+ <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (iterate), or graduates the entry to the next pipeline stage (approve). Iterate is stage-gated — only available on Ideas / Planned / Outlining / Drafting; Final locks content. The review is keyed by entry uuid, not workflow id.</p>
245
245
  <h4>Shortform review</h4>
246
246
  <p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
247
247
  <h4>Keyboard</h4>
@@ -259,7 +259,7 @@ function renderStudioSection(): RawHtml {
259
259
  <div class="eh-panel">
260
260
  <p class="eh-panel-head">Secondary surfaces</p>
261
261
  <h4>Entry review</h4>
262
- <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (when iterating), advances state. The review is keyed by entry uuid, not workflow id.</p>
262
+ <p><code>/dev/editorial-review/entry/&lt;uuid&gt;</code>. The current-stage artifact (idea.md, plan.md, outline.md, or index.md) renders inside the review surface. Select text for a margin note; double-click anywhere to edit the markdown in place. The fixed strip's Approve / Iterate / (Reject — disabled, see <a href="https://github.com/audiocontrol-org/deskwork/issues/173">#173</a>) buttons COPY the corresponding skill command (<code>/deskwork:approve &lt;slug&gt;</code>, etc.) to your clipboard — paste into a Claude Code chat to run. The skill reads marginalia, applies editorial judgment, edits the file (iterate), or graduates the entry to the next pipeline stage (approve). Iterate is stage-gated — only available on Ideas / Planned / Outlining / Drafting; Final locks content. The review is keyed by entry uuid, not workflow id.</p>
263
263
  <h4>Shortform review</h4>
264
264
  <p><code>/dev/editorial-review-shortform</code>. Cards grouped by platform. Each card has a version header, an editable textarea, and save · approve · iterate · reject controls.</p>
265
265
  <h4>Keyboard</h4>
@@ -20,13 +20,15 @@ import type { Entry } from '@deskwork/core/schema/entry';
20
20
  import type { StudioContext } from '../routes/api.ts';
21
21
  /**
22
22
  * Pick the entry that should be the default Longform-reviews target —
23
- * the most-recent in-pipeline entry whose review state is in-review or
24
- * iterating. Returns null when no candidate exists; the caller falls
25
- * back to the dashboard's Review section anchor.
23
+ * the most-recently-updated entry in a stage that permits edits
24
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
25
+ * candidate exists.
26
26
  *
27
- * Replaces the legacy workflow-based picker as part of the pipeline
28
- * redesign (Task 36) the studio's review surfaces are now keyed by
29
- * entry uuid, not workflow uuid.
27
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
28
+ * (in-review / iterating) is retired. Stage IS the state machine; the
29
+ * editable-stage filter approximates "the entry the operator is most
30
+ * likely actively working on" without depending on the retired
31
+ * reviewState concept.
30
32
  */
31
33
  export declare function pickDefaultLongformEntry(entries: readonly Entry[]): Entry | null;
32
34
  export declare function renderStudioIndex(ctx: StudioContext): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqDtD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,KAAK,GAAG,IAAI,CAOd;AAkKD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqDtD;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,KAAK,EAAE,GACxB,KAAK,GAAG,IAAI,CAMd;AAmKD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B3E"}
@@ -30,18 +30,19 @@ const LONGFORM_PIPELINE_STAGES = new Set([
30
30
  ]);
31
31
  /**
32
32
  * Pick the entry that should be the default Longform-reviews target —
33
- * the most-recent in-pipeline entry whose review state is in-review or
34
- * iterating. Returns null when no candidate exists; the caller falls
35
- * back to the dashboard's Review section anchor.
33
+ * the most-recently-updated entry in a stage that permits edits
34
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
35
+ * candidate exists.
36
36
  *
37
- * Replaces the legacy workflow-based picker as part of the pipeline
38
- * redesign (Task 36) the studio's review surfaces are now keyed by
39
- * entry uuid, not workflow uuid.
37
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
38
+ * (in-review / iterating) is retired. Stage IS the state machine; the
39
+ * editable-stage filter approximates "the entry the operator is most
40
+ * likely actively working on" without depending on the retired
41
+ * reviewState concept.
40
42
  */
41
43
  export function pickDefaultLongformEntry(entries) {
42
44
  const candidates = entries
43
45
  .filter((e) => LONGFORM_PIPELINE_STAGES.has(e.currentStage))
44
- .filter((e) => e.reviewState === 'in-review' || e.reviewState === 'iterating')
45
46
  .slice()
46
47
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
47
48
  return candidates[0] ?? null;
@@ -56,13 +57,14 @@ async function buildSections(ctx) {
56
57
  }
57
58
  })();
58
59
  const longformDefaultEntry = pickDefaultLongformEntry(entries);
59
- // Issue #107: III links to the most-recent in-review (or iterating)
60
- // longform entry when one exists, else falls back to the dashboard's
61
- // Review section anchor (`#stage-review`). The link target is the
62
- // entry-keyed review route `/dev/editorial-review/entry/<uuid>`.
60
+ // Issue #107: III links to the most-recently-updated longform entry
61
+ // in a stage that permits edits (Ideas / Planned / Outlining /
62
+ // Drafting), else falls back to the dashboard's Drafting section
63
+ // anchor. The link target is the entry-keyed review route
64
+ // `/dev/editorial-review/entry/<uuid>`.
63
65
  const longformLinkHref = longformDefaultEntry !== null
64
66
  ? `/dev/editorial-review/entry/${longformDefaultEntry.uuid}`
65
- : '/dev/editorial-studio#stage-review';
67
+ : '/dev/editorial-studio#stage-drafting';
66
68
  return [
67
69
  {
68
70
  ornament: '¶',
@@ -100,8 +102,8 @@ async function buildSections(ctx) {
100
102
  desc: 'Per-entry margin notes, decisions, iterate flow.',
101
103
  hint: 'entry-by-entry',
102
104
  postHint: longformDefaultEntry !== null
103
- ? `Defaults to the most-recent in-review longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
104
- : 'Defaults to the dashboard\'s Review section. Open a longform workflow to populate the per-entry deep-link.',
105
+ ? `Defaults to the most-recently-updated longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
106
+ : 'Defaults to the dashboard\'s Drafting section. Add or ingest a longform entry to populate the per-entry deep-link.',
105
107
  },
106
108
  ],
107
109
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pages/index.ts"],"names":[],"mappings":"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"}
@@ -74,20 +74,21 @@ interface IndexSection {
74
74
 
75
75
  /**
76
76
  * Pick the entry that should be the default Longform-reviews target —
77
- * the most-recent in-pipeline entry whose review state is in-review or
78
- * iterating. Returns null when no candidate exists; the caller falls
79
- * back to the dashboard's Review section anchor.
77
+ * the most-recently-updated entry in a stage that permits edits
78
+ * (Ideas / Planned / Outlining / Drafting). Returns null when no
79
+ * candidate exists.
80
80
  *
81
- * Replaces the legacy workflow-based picker as part of the pipeline
82
- * redesign (Task 36) the studio's review surfaces are now keyed by
83
- * entry uuid, not workflow uuid.
81
+ * Per DESKWORK-STATE-MACHINE.md (v5): the previous reviewState filter
82
+ * (in-review / iterating) is retired. Stage IS the state machine; the
83
+ * editable-stage filter approximates "the entry the operator is most
84
+ * likely actively working on" without depending on the retired
85
+ * reviewState concept.
84
86
  */
85
87
  export function pickDefaultLongformEntry(
86
88
  entries: readonly Entry[],
87
89
  ): Entry | null {
88
90
  const candidates = entries
89
91
  .filter((e) => LONGFORM_PIPELINE_STAGES.has(e.currentStage))
90
- .filter((e) => e.reviewState === 'in-review' || e.reviewState === 'iterating')
91
92
  .slice()
92
93
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
93
94
  return candidates[0] ?? null;
@@ -102,14 +103,15 @@ async function buildSections(ctx: StudioContext): Promise<readonly IndexSection[
102
103
  }
103
104
  })();
104
105
  const longformDefaultEntry = pickDefaultLongformEntry(entries);
105
- // Issue #107: III links to the most-recent in-review (or iterating)
106
- // longform entry when one exists, else falls back to the dashboard's
107
- // Review section anchor (`#stage-review`). The link target is the
108
- // entry-keyed review route `/dev/editorial-review/entry/<uuid>`.
106
+ // Issue #107: III links to the most-recently-updated longform entry
107
+ // in a stage that permits edits (Ideas / Planned / Outlining /
108
+ // Drafting), else falls back to the dashboard's Drafting section
109
+ // anchor. The link target is the entry-keyed review route
110
+ // `/dev/editorial-review/entry/<uuid>`.
109
111
  const longformLinkHref =
110
112
  longformDefaultEntry !== null
111
113
  ? `/dev/editorial-review/entry/${longformDefaultEntry.uuid}`
112
- : '/dev/editorial-studio#stage-review';
114
+ : '/dev/editorial-studio#stage-drafting';
113
115
 
114
116
  return [
115
117
  {
@@ -149,8 +151,8 @@ async function buildSections(ctx: StudioContext): Promise<readonly IndexSection[
149
151
  hint: 'entry-by-entry',
150
152
  postHint:
151
153
  longformDefaultEntry !== null
152
- ? `Defaults to the most-recent in-review longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
153
- : 'Defaults to the dashboard\'s Review section. Open a longform workflow to populate the per-entry deep-link.',
154
+ ? `Defaults to the most-recently-updated longform (${longformDefaultEntry.slug}). Or reach via the Dashboard or Content view.`
155
+ : 'Defaults to the dashboard\'s Drafting section. Add or ingest a longform entry to populate the per-entry deep-link.',
154
156
  },
155
157
  ],
156
158
  },
@@ -31,7 +31,7 @@ export function layout(options) {
31
31
  <html lang="en">
32
32
  <head>
33
33
  <meta charset="utf-8">
34
- <meta name="viewport" content="width=device-width, initial-scale=1">
34
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, interactive-widget=resizes-content">
35
35
  <meta name="robots" content="noindex">
36
36
  <title>${escapeHtml(title)}</title>
37
37
  ${cssTags}
@@ -80,7 +80,7 @@ export function layout(options: LayoutOptions): string {
80
80
  <html lang="en">
81
81
  <head>
82
82
  <meta charset="utf-8">
83
- <meta name="viewport" content="width=device-width, initial-scale=1">
83
+ <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, interactive-widget=resizes-content">
84
84
  <meta name="robots" content="noindex">
85
85
  <title>${escapeHtml(title)}</title>
86
86
  ${cssTags}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAwBtE,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA8CpD;AAkFD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyOlD"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAS5B,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAwBtE,UAAU,OAAO;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,qEAAqE;IACrE,WAAW,EAAE,OAAO,CAAC;CACtB;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA8CpD;AAkFD,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAwPlD"}
package/dist/server.js CHANGED
@@ -383,6 +383,17 @@ export function createApp(ctx) {
383
383
  }));
384
384
  // Convenience root redirect to the studio index.
385
385
  app.get('/', (c) => c.redirect('/dev/'));
386
+ // Document root — serves top-level project files (DESKWORK-STATE-MACHINE.md,
387
+ // THESIS.md, README.md, DESIGN-STANDARDS.md, etc.) so the studio's URL
388
+ // namespace mirrors the project filesystem layout. Registered LAST so
389
+ // every more-specific route (`/dev/*`, `/api/*`, `/static/*`, the `/`
390
+ // redirect) matches first; only unmatched paths fall through to a
391
+ // filesystem lookup against the project root. Symlinks in `public/`
392
+ // didn't survive serveStatic's resolution (operator-reported 2026-05-09);
393
+ // serving the project root directly removes the need for symlinks at all.
394
+ app.use('*', serveStatic({
395
+ root: ctx.projectRoot,
396
+ }));
386
397
  return app;
387
398
  }
388
399
  async function main() {
@@ -466,7 +477,7 @@ async function main() {
466
477
  const { join } = await import('node:path');
467
478
  const viteRoot = join(pluginRoot(), 'public');
468
479
  const vite = await createViteServer({
469
- server: { middlewareMode: true },
480
+ server: { middlewareMode: true, allowedHosts: true },
470
481
  appType: 'custom',
471
482
  root: viteRoot,
472
483
  });