@deskwork/studio 0.22.2 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deskwork/studio",
3
- "version": "0.22.2",
3
+ "version": "0.23.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.22.2",
49
+ "@deskwork/core": "0.23.0",
50
50
  "@hono/node-server": "^1.13.7",
51
51
  "@lezer/highlight": "^1.2.3",
52
52
  "@types/diff-match-patch": "^1.0.36",
@@ -1,16 +0,0 @@
1
- /**
2
- * Press-queue sidebar — the dashboard's right column.
3
- *
4
- * "Press-check" gravity: at the press, the operator wants to know what
5
- * needs their eyes RIGHT NOW, separately from the at-a-glance pipeline
6
- * view on the left. This panel surfaces every entry in active review
7
- * (`reviewState === 'in-review'`), longest-waiting first, with a soft
8
- * empty state when the press is quiet.
9
- *
10
- * Closes the long-empty right column the dashboard's `.er-layout` grid
11
- * has been declaring since the surface shipped (#158 child concern).
12
- */
13
- import { type RawHtml } from '../html.ts';
14
- import type { Entry } from '@deskwork/core/schema/entry';
15
- export declare function renderPressQueue(entries: readonly Entry[], defaultSite: string, now: Date): RawHtml;
16
- //# sourceMappingURL=press-queue.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"press-queue.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/press-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,6BAA6B,CAAC;AAsEhE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,IAAI,GACR,OAAO,CAuBT"}
@@ -1,91 +0,0 @@
1
- /**
2
- * Press-queue sidebar — the dashboard's right column.
3
- *
4
- * "Press-check" gravity: at the press, the operator wants to know what
5
- * needs their eyes RIGHT NOW, separately from the at-a-glance pipeline
6
- * view on the left. This panel surfaces every entry in active review
7
- * (`reviewState === 'in-review'`), longest-waiting first, with a soft
8
- * empty state when the press is quiet.
9
- *
10
- * Closes the long-empty right column the dashboard's `.er-layout` grid
11
- * has been declaring since the surface shipped (#158 child concern).
12
- */
13
- import { html, unsafe } from "../html.js";
14
- import { formatRelativeTime } from '@deskwork/core/scrapbook';
15
- const STAGE_ORNAMENTS = {
16
- Ideas: '◇',
17
- Planned: '§',
18
- Outlining: '⊹',
19
- Drafting: '✎',
20
- Final: '※',
21
- Published: '✓',
22
- Blocked: '⊘',
23
- Cancelled: '✗',
24
- };
25
- /**
26
- * Filter the dashboard's entries to those currently in review and
27
- * sort longest-waiting first. The "longest waiting" axis is `updatedAt`
28
- * — every iterate / review-state-change writes to it, so the entry
29
- * whose updatedAt is oldest is the one the operator has been ignoring
30
- * longest.
31
- */
32
- function selectAwaitingItems(entries, now) {
33
- const items = [];
34
- for (const entry of entries) {
35
- if (entry.reviewState !== 'in-review')
36
- continue;
37
- const updatedAt = new Date(entry.updatedAt).getTime();
38
- items.push({ entry, waitedMs: now.getTime() - updatedAt });
39
- }
40
- items.sort((a, b) => b.waitedMs - a.waitedMs);
41
- return items;
42
- }
43
- function renderItem(item, defaultSite, now) {
44
- const { entry } = item;
45
- void defaultSite;
46
- const reviewLink = `/dev/editorial-review/entry/${entry.uuid}`;
47
- return unsafe(html `
48
- <li class="er-press-queue__item" data-stage="${entry.currentStage}">
49
- <a class="er-press-queue__link" href="${reviewLink}">
50
- <span class="er-press-queue__ornament" aria-hidden="true">${STAGE_ORNAMENTS[entry.currentStage]}</span>
51
- <span class="er-press-queue__body">
52
- <span class="er-press-queue__slug">${entry.slug}</span>
53
- <span class="er-press-queue__meta">
54
- <span class="er-press-queue__stage">${entry.currentStage}</span>
55
- <span class="er-press-queue__sep" aria-hidden="true">·</span>
56
- <span class="er-press-queue__waited">${formatRelativeTime(entry.updatedAt, now)}</span>
57
- </span>
58
- </span>
59
- </a>
60
- </li>`);
61
- }
62
- function renderEmptyState() {
63
- return unsafe(html `
64
- <div class="er-press-queue__empty">
65
- <span class="er-press-queue__empty-mark" aria-hidden="true">※</span>
66
- <p class="er-press-queue__empty-line">The press is quiet.</p>
67
- <p class="er-press-queue__empty-hint">Nothing in review.</p>
68
- </div>`);
69
- }
70
- export function renderPressQueue(entries, defaultSite, now) {
71
- const items = selectAwaitingItems(entries, now);
72
- const body = items.length === 0
73
- ? renderEmptyState()
74
- : unsafe(html `
75
- <ol class="er-press-queue__list">
76
- ${unsafe(items
77
- .map((item) => renderItem(item, defaultSite, now).__raw)
78
- .join('\n'))}
79
- </ol>`);
80
- return unsafe(html `
81
- <aside class="er-press-queue${items.length === 0 ? ' er-press-queue--empty' : ''}"
82
- aria-label="Awaiting your eyes">
83
- <header class="er-press-queue__head">
84
- <p class="er-press-queue__kicker">Press queue</p>
85
- <h2 class="er-press-queue__title">Awaiting your <em>eyes</em></h2>
86
- <p class="er-press-queue__count">№ ${items.length}</p>
87
- </header>
88
- ${body}
89
- </aside>`);
90
- }
91
- //# sourceMappingURL=press-queue.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"press-queue.js","sourceRoot":"","sources":["../../../src/pages/dashboard/press-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,MAAM,eAAe,GAA0B;IAC7C,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,GAAG;IACb,KAAK,EAAE,GAAG;IACV,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;CACf,CAAC;AAOF;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,OAAyB,EAAE,GAAS;IAC/D,MAAM,KAAK,GAAmB,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW;YAAE,SAAS;QAChD,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC9C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CACjB,IAAkB,EAClB,WAAmB,EACnB,GAAS;IAET,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IACvB,KAAK,WAAW,CAAC;IACjB,MAAM,UAAU,GAAG,+BAA+B,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAA;mDAC+B,KAAK,CAAC,YAAY;8CACvB,UAAU;oEACY,eAAe,CAAC,KAAK,CAAC,YAAY,CAAC;;+CAExD,KAAK,CAAC,IAAI;;kDAEP,KAAK,CAAC,YAAY;;mDAEjB,kBAAkB,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC;;;;UAIjF,CAAC,CAAC;AACZ,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;WAKT,CAAC,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,OAAyB,EACzB,WAAmB,EACnB,GAAS;IAET,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GACR,KAAK,CAAC,MAAM,KAAK,CAAC;QAChB,CAAC,CAAC,gBAAgB,EAAE;QACpB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAA;;cAEL,MAAM,CACN,KAAK;aACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC;aACvD,IAAI,CAAC,IAAI,CAAC,CACd;gBACG,CAAC,CAAC;IAChB,OAAO,MAAM,CAAC,IAAI,CAAA;kCACc,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE;;;;;6CAKvC,KAAK,CAAC,MAAM;;QAEjD,IAAI;aACC,CAAC,CAAC;AACf,CAAC"}
@@ -1,112 +0,0 @@
1
- /**
2
- * Press-queue sidebar — the dashboard's right column.
3
- *
4
- * "Press-check" gravity: at the press, the operator wants to know what
5
- * needs their eyes RIGHT NOW, separately from the at-a-glance pipeline
6
- * view on the left. This panel surfaces every entry in active review
7
- * (`reviewState === 'in-review'`), longest-waiting first, with a soft
8
- * empty state when the press is quiet.
9
- *
10
- * Closes the long-empty right column the dashboard's `.er-layout` grid
11
- * has been declaring since the surface shipped (#158 child concern).
12
- */
13
-
14
- import { html, unsafe, type RawHtml } from '../html.ts';
15
- import type { Entry, Stage } from '@deskwork/core/schema/entry';
16
- import { formatRelativeTime } from '@deskwork/core/scrapbook';
17
-
18
- const STAGE_ORNAMENTS: Record<Stage, string> = {
19
- Ideas: '◇',
20
- Planned: '§',
21
- Outlining: '⊹',
22
- Drafting: '✎',
23
- Final: '※',
24
- Published: '✓',
25
- Blocked: '⊘',
26
- Cancelled: '✗',
27
- };
28
-
29
- interface AwaitingItem {
30
- readonly entry: Entry;
31
- readonly waitedMs: number;
32
- }
33
-
34
- /**
35
- * Filter the dashboard's entries to those currently in review and
36
- * sort longest-waiting first. The "longest waiting" axis is `updatedAt`
37
- * — every iterate / review-state-change writes to it, so the entry
38
- * whose updatedAt is oldest is the one the operator has been ignoring
39
- * longest.
40
- */
41
- function selectAwaitingItems(entries: readonly Entry[], now: Date): AwaitingItem[] {
42
- const items: AwaitingItem[] = [];
43
- for (const entry of entries) {
44
- if (entry.reviewState !== 'in-review') continue;
45
- const updatedAt = new Date(entry.updatedAt).getTime();
46
- items.push({ entry, waitedMs: now.getTime() - updatedAt });
47
- }
48
- items.sort((a, b) => b.waitedMs - a.waitedMs);
49
- return items;
50
- }
51
-
52
- function renderItem(
53
- item: AwaitingItem,
54
- defaultSite: string,
55
- now: Date,
56
- ): RawHtml {
57
- const { entry } = item;
58
- void defaultSite;
59
- const reviewLink = `/dev/editorial-review/entry/${entry.uuid}`;
60
- return unsafe(html`
61
- <li class="er-press-queue__item" data-stage="${entry.currentStage}">
62
- <a class="er-press-queue__link" href="${reviewLink}">
63
- <span class="er-press-queue__ornament" aria-hidden="true">${STAGE_ORNAMENTS[entry.currentStage]}</span>
64
- <span class="er-press-queue__body">
65
- <span class="er-press-queue__slug">${entry.slug}</span>
66
- <span class="er-press-queue__meta">
67
- <span class="er-press-queue__stage">${entry.currentStage}</span>
68
- <span class="er-press-queue__sep" aria-hidden="true">·</span>
69
- <span class="er-press-queue__waited">${formatRelativeTime(entry.updatedAt, now)}</span>
70
- </span>
71
- </span>
72
- </a>
73
- </li>`);
74
- }
75
-
76
- function renderEmptyState(): RawHtml {
77
- return unsafe(html`
78
- <div class="er-press-queue__empty">
79
- <span class="er-press-queue__empty-mark" aria-hidden="true">※</span>
80
- <p class="er-press-queue__empty-line">The press is quiet.</p>
81
- <p class="er-press-queue__empty-hint">Nothing in review.</p>
82
- </div>`);
83
- }
84
-
85
- export function renderPressQueue(
86
- entries: readonly Entry[],
87
- defaultSite: string,
88
- now: Date,
89
- ): RawHtml {
90
- const items = selectAwaitingItems(entries, now);
91
- const body =
92
- items.length === 0
93
- ? renderEmptyState()
94
- : unsafe(html`
95
- <ol class="er-press-queue__list">
96
- ${unsafe(
97
- items
98
- .map((item) => renderItem(item, defaultSite, now).__raw)
99
- .join('\n'),
100
- )}
101
- </ol>`);
102
- return unsafe(html`
103
- <aside class="er-press-queue${items.length === 0 ? ' er-press-queue--empty' : ''}"
104
- aria-label="Awaiting your eyes">
105
- <header class="er-press-queue__head">
106
- <p class="er-press-queue__kicker">Press queue</p>
107
- <h2 class="er-press-queue__title">Awaiting your <em>eyes</em></h2>
108
- <p class="er-press-queue__count">№ ${items.length}</p>
109
- </header>
110
- ${body}
111
- </aside>`);
112
- }
@@ -1,62 +0,0 @@
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 { type RawHtml } from '../html.ts';
41
- export declare function renderMobileBar(): RawHtml;
42
- export declare function renderMobileSheet(): RawHtml;
43
- /**
44
- * Phone-only Source/Preview pill rendered into the top strip when in
45
- * edit mode. Uses the same `data-edit-view` attribute as the desktop
46
- * edit toolbar so `editModeBtns` (queried via that attribute in
47
- * entry-review-client.ts) auto-binds clicks. CSS reveals it only on
48
- * phone + edit mode; the desktop edit toolbar is hidden in that
49
- * combination.
50
- */
51
- export declare function renderStripModeSegment(): RawHtml;
52
- /**
53
- * Phone-only "✕ Done" exit affordance in the strip. Visible only when
54
- * editing on phone (CSS-gated). Click dispatches into the existing
55
- * toggle-edit handler — preserves the confirmDiscard prompt when the
56
- * buffer is dirty, immediate exit when clean. Sits alongside the
57
- * existing back-link (which continues to navigate home regardless of
58
- * mode) so the operator always has both "leave editor" and "leave
59
- * page" affordances available.
60
- */
61
- export declare function renderStripEditExit(): RawHtml;
62
- //# sourceMappingURL=mobile-bar.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobile-bar.d.ts","sourceRoot":"","sources":["../../../src/pages/entry-review/mobile-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,wBAAgB,eAAe,IAAI,OAAO,CA8BzC;AA2BD,wBAAgB,iBAAiB,IAAI,OAAO,CA2B3C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAMhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAM7C"}
@@ -1,155 +0,0 @@
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
@@ -1 +0,0 @@
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"}