@deskwork/studio 0.21.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.
Files changed (67) hide show
  1. package/dist/pages/dashboard/adjacent-section.d.ts +38 -0
  2. package/dist/pages/dashboard/adjacent-section.d.ts.map +1 -0
  3. package/dist/pages/dashboard/adjacent-section.js +61 -0
  4. package/dist/pages/dashboard/adjacent-section.js.map +1 -0
  5. package/dist/pages/dashboard/adjacent-section.ts +71 -0
  6. package/dist/pages/dashboard/data.d.ts +35 -4
  7. package/dist/pages/dashboard/data.d.ts.map +1 -1
  8. package/dist/pages/dashboard/data.js +69 -5
  9. package/dist/pages/dashboard/data.js.map +1 -1
  10. package/dist/pages/dashboard/data.ts +84 -5
  11. package/dist/pages/dashboard/press-queue.d.ts +16 -0
  12. package/dist/pages/dashboard/press-queue.d.ts.map +1 -0
  13. package/dist/pages/dashboard/press-queue.js +91 -0
  14. package/dist/pages/dashboard/press-queue.js.map +1 -0
  15. package/dist/pages/dashboard/press-queue.ts +112 -0
  16. package/dist/pages/dashboard/section.d.ts.map +1 -1
  17. package/dist/pages/dashboard/section.js +7 -0
  18. package/dist/pages/dashboard/section.js.map +1 -1
  19. package/dist/pages/dashboard/section.ts +7 -0
  20. package/dist/pages/dashboard/shortform-section.d.ts +86 -0
  21. package/dist/pages/dashboard/shortform-section.d.ts.map +1 -0
  22. package/dist/pages/dashboard/shortform-section.js +189 -0
  23. package/dist/pages/dashboard/shortform-section.js.map +1 -0
  24. package/dist/pages/dashboard/shortform-section.ts +228 -0
  25. package/dist/pages/dashboard.d.ts.map +1 -1
  26. package/dist/pages/dashboard.js +34 -1
  27. package/dist/pages/dashboard.js.map +1 -1
  28. package/dist/pages/dashboard.ts +40 -1
  29. package/dist/pages/entry-review/index.d.ts.map +1 -1
  30. package/dist/pages/entry-review/index.js +24 -2
  31. package/dist/pages/entry-review/index.js.map +1 -1
  32. package/dist/pages/entry-review/mobile-sheet.d.ts +65 -0
  33. package/dist/pages/entry-review/mobile-sheet.d.ts.map +1 -0
  34. package/dist/pages/entry-review/mobile-sheet.js +170 -0
  35. package/dist/pages/entry-review/mobile-sheet.js.map +1 -0
  36. package/dist/pages/masthead-menu.d.ts +38 -0
  37. package/dist/pages/masthead-menu.d.ts.map +1 -0
  38. package/dist/pages/masthead-menu.js +126 -0
  39. package/dist/pages/masthead-menu.js.map +1 -0
  40. package/dist/pages/masthead-menu.ts +128 -0
  41. package/dist/pages/masthead.d.ts +85 -0
  42. package/dist/pages/masthead.d.ts.map +1 -0
  43. package/dist/pages/masthead.js +99 -0
  44. package/dist/pages/masthead.js.map +1 -0
  45. package/dist/pages/masthead.ts +155 -0
  46. package/dist/pages/mobile-bar.d.ts +72 -0
  47. package/dist/pages/mobile-bar.d.ts.map +1 -0
  48. package/dist/pages/mobile-bar.js +88 -0
  49. package/dist/pages/mobile-bar.js.map +1 -0
  50. package/dist/pages/mobile-bar.ts +129 -0
  51. package/dist/pages/shortform-review-mobile-sheet.d.ts +76 -0
  52. package/dist/pages/shortform-review-mobile-sheet.d.ts.map +1 -0
  53. package/dist/pages/shortform-review-mobile-sheet.js +159 -0
  54. package/dist/pages/shortform-review-mobile-sheet.js.map +1 -0
  55. package/dist/pages/shortform-review-mobile-sheet.ts +185 -0
  56. package/dist/pages/shortform-review.d.ts +18 -0
  57. package/dist/pages/shortform-review.d.ts.map +1 -1
  58. package/dist/pages/shortform-review.js +62 -111
  59. package/dist/pages/shortform-review.js.map +1 -1
  60. package/dist/pages/shortform-review.ts +68 -140
  61. package/dist/pages/shortform.d.ts.map +1 -1
  62. package/dist/pages/shortform.js +0 -1
  63. package/dist/pages/shortform.js.map +1 -1
  64. package/dist/pages/shortform.ts +0 -1
  65. package/dist/server.js +41 -1
  66. package/dist/server.js.map +1 -1
  67. package/package.json +2 -2
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Adjacent-tools section renderer (Step 2.2.9 — studio-mobile-first).
3
+ *
4
+ * Per DESIGN-STANDARDS.md § Desk information architecture, the Desk's
5
+ * third section reserves space for Phase 3+ surfaces — Folio (standalone
6
+ * scrapbook viewer) and Files (content tree). These render as inert
7
+ * "future tiles" — visible but non-interactive — tagged `phase 3` so the
8
+ * operator sees what's coming without being able to tap a dead control.
9
+ *
10
+ * Per DESIGN-STANDARDS.md § Accessibility / Contrast, future tiles
11
+ * demote via explicit muted palette (NOT opacity reduction). All body
12
+ * text reads at ≥4.5:1 against the tile background; the ornamental
13
+ * border + glyph read at ≥3:1.
14
+ *
15
+ * The future tiles deliberately render as `<div>` (not `<button>`) — no
16
+ * interactive markup — so the stage-tiles.ts controller leaves them
17
+ * alone and assistive tech doesn't announce a disabled control. The
18
+ * `aria-disabled="true"` attribute communicates the inert state to AT.
19
+ * The `<div>`'s implicit `generic` role is preserved (no `role=
20
+ * presentation` override); per WAI-ARIA the generic role honors
21
+ * `aria-disabled` state, whereas `role="presentation"` would strip
22
+ * the element of all semantic identity and nullify the aria attribute.
23
+ */
24
+ import { type RawHtml } from '../html.ts';
25
+ /**
26
+ * Render the adjacent-tools section head — `<div class="er-desk-section-head
27
+ * er-desk-section-head--adjacent">` matching the mockup's
28
+ * `.desk-section-head.adjacent` shape. Kraft-colored glyph + label +
29
+ * "phase 3" caption.
30
+ */
31
+ export declare function renderAdjacentSectionHead(): RawHtml;
32
+ /**
33
+ * Compose the adjacent-tools section: section head + 2 future tiles
34
+ * (Folio + Files). No tap targets, no `data-stage-tile` attrs — these
35
+ * are structurally inert placeholders until Phase 3+ wires them.
36
+ */
37
+ export declare function renderAdjacentSection(): RawHtml;
38
+ //# sourceMappingURL=adjacent-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adjacent-section.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/adjacent-section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAaxD;;;;;GAKG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAOnD;AAWD;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAI/C"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Adjacent-tools section renderer (Step 2.2.9 — studio-mobile-first).
3
+ *
4
+ * Per DESIGN-STANDARDS.md § Desk information architecture, the Desk's
5
+ * third section reserves space for Phase 3+ surfaces — Folio (standalone
6
+ * scrapbook viewer) and Files (content tree). These render as inert
7
+ * "future tiles" — visible but non-interactive — tagged `phase 3` so the
8
+ * operator sees what's coming without being able to tap a dead control.
9
+ *
10
+ * Per DESIGN-STANDARDS.md § Accessibility / Contrast, future tiles
11
+ * demote via explicit muted palette (NOT opacity reduction). All body
12
+ * text reads at ≥4.5:1 against the tile background; the ornamental
13
+ * border + glyph read at ≥3:1.
14
+ *
15
+ * The future tiles deliberately render as `<div>` (not `<button>`) — no
16
+ * interactive markup — so the stage-tiles.ts controller leaves them
17
+ * alone and assistive tech doesn't announce a disabled control. The
18
+ * `aria-disabled="true"` attribute communicates the inert state to AT.
19
+ * The `<div>`'s implicit `generic` role is preserved (no `role=
20
+ * presentation` override); per WAI-ARIA the generic role honors
21
+ * `aria-disabled` state, whereas `role="presentation"` would strip
22
+ * the element of all semantic identity and nullify the aria attribute.
23
+ */
24
+ import { html, unsafe } from "../html.js";
25
+ const FUTURE_TILES = [
26
+ { glyph: '▦', name: 'Folio (standalone)', tag: 'phase 3' },
27
+ { glyph: '⊞', name: 'Files (content tree)', tag: 'phase 3' },
28
+ ];
29
+ /**
30
+ * Render the adjacent-tools section head — `<div class="er-desk-section-head
31
+ * er-desk-section-head--adjacent">` matching the mockup's
32
+ * `.desk-section-head.adjacent` shape. Kraft-colored glyph + label +
33
+ * "phase 3" caption.
34
+ */
35
+ export function renderAdjacentSectionHead() {
36
+ return unsafe(html `
37
+ <div class="er-desk-section-head er-desk-section-head--adjacent">
38
+ <span class="er-desk-section-head-glyph" aria-hidden="true">▦</span>
39
+ <span class="er-desk-section-head-label">Adjacent tools</span>
40
+ <span class="er-desk-section-head-count">· phase 3</span>
41
+ </div>`);
42
+ }
43
+ function renderFutureTile(tile) {
44
+ return unsafe(html `
45
+ <div class="er-future-tile" aria-disabled="true">
46
+ <span class="er-future-tile-glyph" aria-hidden="true">${tile.glyph}</span>
47
+ <span class="er-future-tile-name">${tile.name}</span>
48
+ <span class="er-future-tile-tag">${tile.tag}</span>
49
+ </div>`);
50
+ }
51
+ /**
52
+ * Compose the adjacent-tools section: section head + 2 future tiles
53
+ * (Folio + Files). No tap targets, no `data-stage-tile` attrs — these
54
+ * are structurally inert placeholders until Phase 3+ wires them.
55
+ */
56
+ export function renderAdjacentSection() {
57
+ const sectionHead = renderAdjacentSectionHead();
58
+ const tiles = FUTURE_TILES.map((t) => renderFutureTile(t).__raw).join('');
59
+ return unsafe(html `${sectionHead}${unsafe(tiles)}`);
60
+ }
61
+ //# sourceMappingURL=adjacent-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adjacent-section.js","sourceRoot":"","sources":["../../../src/pages/dashboard/adjacent-section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AAQxD,MAAM,YAAY,GAA0B;IAC1C,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,oBAAoB,EAAE,GAAG,EAAE,SAAS,EAAE;IAC1D,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,sBAAsB,EAAE,GAAG,EAAE,SAAS,EAAE;CACpD,CAAC;AAEX;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;WAKT,CAAC,CAAC;AACb,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAgB;IACxC,OAAO,MAAM,CAAC,IAAI,CAAA;;8DAE0C,IAAI,CAAC,KAAK;0CAC9B,IAAI,CAAC,IAAI;yCACV,IAAI,CAAC,GAAG;WACtC,CAAC,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB;IACnC,MAAM,WAAW,GAAG,yBAAyB,EAAE,CAAC;IAChD,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1E,OAAO,MAAM,CAAC,IAAI,CAAA,GAAG,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Adjacent-tools section renderer (Step 2.2.9 — studio-mobile-first).
3
+ *
4
+ * Per DESIGN-STANDARDS.md § Desk information architecture, the Desk's
5
+ * third section reserves space for Phase 3+ surfaces — Folio (standalone
6
+ * scrapbook viewer) and Files (content tree). These render as inert
7
+ * "future tiles" — visible but non-interactive — tagged `phase 3` so the
8
+ * operator sees what's coming without being able to tap a dead control.
9
+ *
10
+ * Per DESIGN-STANDARDS.md § Accessibility / Contrast, future tiles
11
+ * demote via explicit muted palette (NOT opacity reduction). All body
12
+ * text reads at ≥4.5:1 against the tile background; the ornamental
13
+ * border + glyph read at ≥3:1.
14
+ *
15
+ * The future tiles deliberately render as `<div>` (not `<button>`) — no
16
+ * interactive markup — so the stage-tiles.ts controller leaves them
17
+ * alone and assistive tech doesn't announce a disabled control. The
18
+ * `aria-disabled="true"` attribute communicates the inert state to AT.
19
+ * The `<div>`'s implicit `generic` role is preserved (no `role=
20
+ * presentation` override); per WAI-ARIA the generic role honors
21
+ * `aria-disabled` state, whereas `role="presentation"` would strip
22
+ * the element of all semantic identity and nullify the aria attribute.
23
+ */
24
+
25
+ import { html, unsafe, type RawHtml } from '../html.ts';
26
+
27
+ interface FutureTile {
28
+ readonly glyph: string;
29
+ readonly name: string;
30
+ readonly tag: string;
31
+ }
32
+
33
+ const FUTURE_TILES: readonly FutureTile[] = [
34
+ { glyph: '▦', name: 'Folio (standalone)', tag: 'phase 3' },
35
+ { glyph: '⊞', name: 'Files (content tree)', tag: 'phase 3' },
36
+ ] as const;
37
+
38
+ /**
39
+ * Render the adjacent-tools section head — `<div class="er-desk-section-head
40
+ * er-desk-section-head--adjacent">` matching the mockup's
41
+ * `.desk-section-head.adjacent` shape. Kraft-colored glyph + label +
42
+ * "phase 3" caption.
43
+ */
44
+ export function renderAdjacentSectionHead(): RawHtml {
45
+ return unsafe(html`
46
+ <div class="er-desk-section-head er-desk-section-head--adjacent">
47
+ <span class="er-desk-section-head-glyph" aria-hidden="true">▦</span>
48
+ <span class="er-desk-section-head-label">Adjacent tools</span>
49
+ <span class="er-desk-section-head-count">· phase 3</span>
50
+ </div>`);
51
+ }
52
+
53
+ function renderFutureTile(tile: FutureTile): RawHtml {
54
+ return unsafe(html`
55
+ <div class="er-future-tile" aria-disabled="true">
56
+ <span class="er-future-tile-glyph" aria-hidden="true">${tile.glyph}</span>
57
+ <span class="er-future-tile-name">${tile.name}</span>
58
+ <span class="er-future-tile-tag">${tile.tag}</span>
59
+ </div>`);
60
+ }
61
+
62
+ /**
63
+ * Compose the adjacent-tools section: section head + 2 future tiles
64
+ * (Folio + Files). No tap targets, no `data-stage-tile` attrs — these
65
+ * are structurally inert placeholders until Phase 3+ wires them.
66
+ */
67
+ export function renderAdjacentSection(): RawHtml {
68
+ const sectionHead = renderAdjacentSectionHead();
69
+ const tiles = FUTURE_TILES.map((t) => renderFutureTile(t).__raw).join('');
70
+ return unsafe(html`${sectionHead}${unsafe(tiles)}`);
71
+ }
@@ -4,11 +4,19 @@
4
4
  * `currentStage` so the renderer can iterate the eight canonical
5
5
  * stage sections without re-walking the disk per stage.
6
6
  *
7
- * Pipeline-redesign Task 34. Replaces the legacy
8
- * `loadDashboardData` (calendar.md + workflow store) with a
9
- * sidecar-only reader.
7
+ * v7 architecture (Step 2.2.9 studio-mobile-first feature): also
8
+ * reads open shortform workflows from the review-pipeline store and
9
+ * groups them by `Platform`. Per DESIGN-STANDARDS.md § Desk
10
+ * information architecture, the Desk absorbs the Shortform-by-platform
11
+ * view as its second section (sibling of the longform pipeline). The
12
+ * v0.21 platform display order is LinkedIn → Reddit → YouTube →
13
+ * Instagram (insertion order = display order; verified against the
14
+ * v7 mockup at desk-states-v7.html:632-655).
10
15
  */
11
16
  import type { Entry, Stage } from '@deskwork/core/schema/entry';
17
+ import type { DraftWorkflowItem } from '@deskwork/core/review/types';
18
+ import type { Platform } from '@deskwork/core/types';
19
+ import type { DeskworkConfig } from '@deskwork/core/config';
12
20
  /**
13
21
  * The eight canonical stages, in display order. Linear pipeline
14
22
  * (Ideas → Published) first, then off-pipeline (Blocked, Cancelled)
@@ -16,9 +24,32 @@ import type { Entry, Stage } from '@deskwork/core/schema/entry';
16
24
  * normal lifecycle.
17
25
  */
18
26
  export declare const DASHBOARD_STAGE_ORDER: readonly Stage[];
27
+ /**
28
+ * Display order for shortform platform tiles. Verified against the v7
29
+ * mockup at desk-states-v7.html:632-655: LinkedIn → Reddit → YouTube →
30
+ * Instagram. Used as the insertion order for the `shortformByPlatform`
31
+ * Map so iteration order matches display order.
32
+ */
33
+ export declare const DASHBOARD_PLATFORM_ORDER: readonly Platform[];
19
34
  export interface DashboardData {
20
35
  readonly entries: readonly Entry[];
21
36
  readonly byStage: ReadonlyMap<Stage, readonly Entry[]>;
37
+ readonly shortformWorkflows: readonly DraftWorkflowItem[];
38
+ readonly shortformByPlatform: ReadonlyMap<Platform, readonly DraftWorkflowItem[]>;
22
39
  }
23
- export declare function loadDashboardData(projectRoot: string): Promise<DashboardData>;
40
+ /**
41
+ * Bucket shortform workflows by platform. Insertion order matches
42
+ * `DASHBOARD_PLATFORM_ORDER` — even empty platforms get a Map entry so
43
+ * the renderer can iterate the four canonical tiles uniformly.
44
+ *
45
+ * Throws on a workflow whose `platform` is undefined. Per project rule
46
+ * "Never implement fallbacks or use mock data outside of test code" — a
47
+ * shortform workflow without a platform is a data-integrity bug
48
+ * upstream, not a case to silently drop. Throwing surfaces the bug;
49
+ * silent-drop would hide missing-from-the-Desk rows behind a count that
50
+ * disagrees with the workflow store.
51
+ */
52
+ /** @internal — exported only for testability of the throw contract. */
53
+ export declare function bucketizeShortform(workflows: readonly DraftWorkflowItem[]): Map<Platform, DraftWorkflowItem[]>;
54
+ export declare function loadDashboardData(projectRoot: string, config: DeskworkConfig): Promise<DashboardData>;
24
55
  //# sourceMappingURL=data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,KAAK,EASxC,CAAC;AAEX,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;CACxD;AAiBD,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAInF"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,KAAK,EASxC,CAAC;AAEX;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,QAAQ,EAK9C,CAAC;AAEX,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,KAAK,EAAE,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,KAAK,EAAE,SAAS,KAAK,EAAE,CAAC,CAAC;IACvD,QAAQ,CAAC,kBAAkB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC,CAAC;CACnF;AAkCD;;;;;;;;;;;GAWG;AACH,uEAAuE;AACvE,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,SAAS,iBAAiB,EAAE,GACtC,GAAG,CAAC,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAgBpC;AAED,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,aAAa,CAAC,CAMxB"}
@@ -4,11 +4,17 @@
4
4
  * `currentStage` so the renderer can iterate the eight canonical
5
5
  * stage sections without re-walking the disk per stage.
6
6
  *
7
- * Pipeline-redesign Task 34. Replaces the legacy
8
- * `loadDashboardData` (calendar.md + workflow store) with a
9
- * sidecar-only reader.
7
+ * v7 architecture (Step 2.2.9 studio-mobile-first feature): also
8
+ * reads open shortform workflows from the review-pipeline store and
9
+ * groups them by `Platform`. Per DESIGN-STANDARDS.md § Desk
10
+ * information architecture, the Desk absorbs the Shortform-by-platform
11
+ * view as its second section (sibling of the longform pipeline). The
12
+ * v0.21 platform display order is LinkedIn → Reddit → YouTube →
13
+ * Instagram (insertion order = display order; verified against the
14
+ * v7 mockup at desk-states-v7.html:632-655).
10
15
  */
11
16
  import { readAllSidecars } from '@deskwork/core/sidecar';
17
+ import { listOpen } from '@deskwork/core/review/pipeline';
12
18
  /**
13
19
  * The eight canonical stages, in display order. Linear pipeline
14
20
  * (Ideas → Published) first, then off-pipeline (Blocked, Cancelled)
@@ -25,6 +31,18 @@ export const DASHBOARD_STAGE_ORDER = [
25
31
  'Blocked',
26
32
  'Cancelled',
27
33
  ];
34
+ /**
35
+ * Display order for shortform platform tiles. Verified against the v7
36
+ * mockup at desk-states-v7.html:632-655: LinkedIn → Reddit → YouTube →
37
+ * Instagram. Used as the insertion order for the `shortformByPlatform`
38
+ * Map so iteration order matches display order.
39
+ */
40
+ export const DASHBOARD_PLATFORM_ORDER = [
41
+ 'linkedin',
42
+ 'reddit',
43
+ 'youtube',
44
+ 'instagram',
45
+ ];
28
46
  function bucketize(entries) {
29
47
  const out = new Map();
30
48
  for (const stage of DASHBOARD_STAGE_ORDER)
@@ -41,9 +59,55 @@ function bucketize(entries) {
41
59
  }
42
60
  return out;
43
61
  }
44
- export async function loadDashboardData(projectRoot) {
62
+ /**
63
+ * Load open shortform workflows, sorted by `updatedAt` descending.
64
+ * Ported from the pre-v7 `loadOpenShortform` helper in pages/shortform.ts
65
+ * (preserved verbatim there until Step 2.2.10 retires that page).
66
+ */
67
+ function loadOpenShortform(projectRoot, config) {
68
+ const open = [];
69
+ for (const w of listOpen(projectRoot, config)) {
70
+ if (w.contentKind === 'shortform')
71
+ open.push(w);
72
+ }
73
+ open.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
74
+ return open;
75
+ }
76
+ /**
77
+ * Bucket shortform workflows by platform. Insertion order matches
78
+ * `DASHBOARD_PLATFORM_ORDER` — even empty platforms get a Map entry so
79
+ * the renderer can iterate the four canonical tiles uniformly.
80
+ *
81
+ * Throws on a workflow whose `platform` is undefined. Per project rule
82
+ * "Never implement fallbacks or use mock data outside of test code" — a
83
+ * shortform workflow without a platform is a data-integrity bug
84
+ * upstream, not a case to silently drop. Throwing surfaces the bug;
85
+ * silent-drop would hide missing-from-the-Desk rows behind a count that
86
+ * disagrees with the workflow store.
87
+ */
88
+ /** @internal — exported only for testability of the throw contract. */
89
+ export function bucketizeShortform(workflows) {
90
+ const out = new Map();
91
+ for (const platform of DASHBOARD_PLATFORM_ORDER)
92
+ out.set(platform, []);
93
+ for (const w of workflows) {
94
+ if (w.platform === undefined) {
95
+ throw new Error(`Shortform workflow "${w.id}" (slug "${w.slug}") has no platform — ` +
96
+ `the Desk cannot bucket it. This is a data-integrity bug; ` +
97
+ `every shortform workflow must carry a platform per ` +
98
+ `@deskwork/core/review/types DraftWorkflowItem.`);
99
+ }
100
+ const bucket = out.get(w.platform);
101
+ if (bucket !== undefined)
102
+ bucket.push(w);
103
+ }
104
+ return out;
105
+ }
106
+ export async function loadDashboardData(projectRoot, config) {
45
107
  const entries = await readAllSidecars(projectRoot);
46
108
  const byStage = bucketize(entries);
47
- return { entries, byStage };
109
+ const shortformWorkflows = loadOpenShortform(projectRoot, config);
110
+ const shortformByPlatform = bucketizeShortform(shortformWorkflows);
111
+ return { entries, byStage, shortformWorkflows, shortformByPlatform };
48
112
  }
49
113
  //# sourceMappingURL=data.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sourceRoot":"","sources":["../../../src/pages/dashboard/data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAqB;IACrD,OAAO;IACP,SAAS;IACT,WAAW;IACX,UAAU;IACV,OAAO;IACP,WAAW;IACX,SAAS;IACT,WAAW;CACH,CAAC;AAOX,SAAS,SAAS,CAAC,OAAyB;IAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,qBAAqB;QAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,gEAAgE;IAChE,8DAA8D;IAC9D,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IACzD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../../src/pages/dashboard/data.ts"],"names":[],"mappings":"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"}
@@ -4,13 +4,22 @@
4
4
  * `currentStage` so the renderer can iterate the eight canonical
5
5
  * stage sections without re-walking the disk per stage.
6
6
  *
7
- * Pipeline-redesign Task 34. Replaces the legacy
8
- * `loadDashboardData` (calendar.md + workflow store) with a
9
- * sidecar-only reader.
7
+ * v7 architecture (Step 2.2.9 studio-mobile-first feature): also
8
+ * reads open shortform workflows from the review-pipeline store and
9
+ * groups them by `Platform`. Per DESIGN-STANDARDS.md § Desk
10
+ * information architecture, the Desk absorbs the Shortform-by-platform
11
+ * view as its second section (sibling of the longform pipeline). The
12
+ * v0.21 platform display order is LinkedIn → Reddit → YouTube →
13
+ * Instagram (insertion order = display order; verified against the
14
+ * v7 mockup at desk-states-v7.html:632-655).
10
15
  */
11
16
 
12
17
  import { readAllSidecars } from '@deskwork/core/sidecar';
13
18
  import type { Entry, Stage } from '@deskwork/core/schema/entry';
19
+ import { listOpen } from '@deskwork/core/review/pipeline';
20
+ import type { DraftWorkflowItem } from '@deskwork/core/review/types';
21
+ import type { Platform } from '@deskwork/core/types';
22
+ import type { DeskworkConfig } from '@deskwork/core/config';
14
23
 
15
24
  /**
16
25
  * The eight canonical stages, in display order. Linear pipeline
@@ -29,9 +38,24 @@ export const DASHBOARD_STAGE_ORDER: readonly Stage[] = [
29
38
  'Cancelled',
30
39
  ] as const;
31
40
 
41
+ /**
42
+ * Display order for shortform platform tiles. Verified against the v7
43
+ * mockup at desk-states-v7.html:632-655: LinkedIn → Reddit → YouTube →
44
+ * Instagram. Used as the insertion order for the `shortformByPlatform`
45
+ * Map so iteration order matches display order.
46
+ */
47
+ export const DASHBOARD_PLATFORM_ORDER: readonly Platform[] = [
48
+ 'linkedin',
49
+ 'reddit',
50
+ 'youtube',
51
+ 'instagram',
52
+ ] as const;
53
+
32
54
  export interface DashboardData {
33
55
  readonly entries: readonly Entry[];
34
56
  readonly byStage: ReadonlyMap<Stage, readonly Entry[]>;
57
+ readonly shortformWorkflows: readonly DraftWorkflowItem[];
58
+ readonly shortformByPlatform: ReadonlyMap<Platform, readonly DraftWorkflowItem[]>;
35
59
  }
36
60
 
37
61
  function bucketize(entries: readonly Entry[]): Map<Stage, Entry[]> {
@@ -49,8 +73,63 @@ function bucketize(entries: readonly Entry[]): Map<Stage, Entry[]> {
49
73
  return out;
50
74
  }
51
75
 
52
- export async function loadDashboardData(projectRoot: string): Promise<DashboardData> {
76
+ /**
77
+ * Load open shortform workflows, sorted by `updatedAt` descending.
78
+ * Ported from the pre-v7 `loadOpenShortform` helper in pages/shortform.ts
79
+ * (preserved verbatim there until Step 2.2.10 retires that page).
80
+ */
81
+ function loadOpenShortform(
82
+ projectRoot: string,
83
+ config: DeskworkConfig,
84
+ ): DraftWorkflowItem[] {
85
+ const open: DraftWorkflowItem[] = [];
86
+ for (const w of listOpen(projectRoot, config)) {
87
+ if (w.contentKind === 'shortform') open.push(w);
88
+ }
89
+ open.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
90
+ return open;
91
+ }
92
+
93
+ /**
94
+ * Bucket shortform workflows by platform. Insertion order matches
95
+ * `DASHBOARD_PLATFORM_ORDER` — even empty platforms get a Map entry so
96
+ * the renderer can iterate the four canonical tiles uniformly.
97
+ *
98
+ * Throws on a workflow whose `platform` is undefined. Per project rule
99
+ * "Never implement fallbacks or use mock data outside of test code" — a
100
+ * shortform workflow without a platform is a data-integrity bug
101
+ * upstream, not a case to silently drop. Throwing surfaces the bug;
102
+ * silent-drop would hide missing-from-the-Desk rows behind a count that
103
+ * disagrees with the workflow store.
104
+ */
105
+ /** @internal — exported only for testability of the throw contract. */
106
+ export function bucketizeShortform(
107
+ workflows: readonly DraftWorkflowItem[],
108
+ ): Map<Platform, DraftWorkflowItem[]> {
109
+ const out = new Map<Platform, DraftWorkflowItem[]>();
110
+ for (const platform of DASHBOARD_PLATFORM_ORDER) out.set(platform, []);
111
+ for (const w of workflows) {
112
+ if (w.platform === undefined) {
113
+ throw new Error(
114
+ `Shortform workflow "${w.id}" (slug "${w.slug}") has no platform — ` +
115
+ `the Desk cannot bucket it. This is a data-integrity bug; ` +
116
+ `every shortform workflow must carry a platform per ` +
117
+ `@deskwork/core/review/types DraftWorkflowItem.`,
118
+ );
119
+ }
120
+ const bucket = out.get(w.platform);
121
+ if (bucket !== undefined) bucket.push(w);
122
+ }
123
+ return out;
124
+ }
125
+
126
+ export async function loadDashboardData(
127
+ projectRoot: string,
128
+ config: DeskworkConfig,
129
+ ): Promise<DashboardData> {
53
130
  const entries = await readAllSidecars(projectRoot);
54
131
  const byStage = bucketize(entries);
55
- return { entries, byStage };
132
+ const shortformWorkflows = loadOpenShortform(projectRoot, config);
133
+ const shortformByPlatform = bucketizeShortform(shortformWorkflows);
134
+ return { entries, byStage, shortformWorkflows, shortformByPlatform };
56
135
  }
@@ -0,0 +1,16 @@
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
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,91 @@
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
@@ -0,0 +1 @@
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"}