@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
@@ -6,37 +6,32 @@
6
6
  * carry a `data-copy` payload that the existing studio client copies
7
7
  * to the clipboard. No new backend handlers are wired here; the
8
8
  * universal-verb skills are the canonical action path.
9
+ *
10
+ * Per DESKWORK-STATE-MACHINE.md (v5):
11
+ * - Verbs are stage-gated, not state-gated. The iterate button shows
12
+ * on stages-that-permit-edits (Ideas/Planned/Outlining/Drafting),
13
+ * not on Final (locked) or Published (immutable).
14
+ * - Revisions (the iteration counter) are bookkeeping. They do not
15
+ * surface in routine UI; the operator only sees them via revision
16
+ * history / revert flows. The previous "iteration: N" per-row
17
+ * display has been removed.
9
18
  */
10
19
  import { type RawHtml } from '../html.ts';
11
- import type { Entry, ReviewState } from '@deskwork/core/schema/entry';
12
- /**
13
- * Render the reviewState badge. When the entry has no reviewState
14
- * (most pre-review stages), render an em-dash placeholder so the row
15
- * stays grid-aligned with sibling rows that DO carry a badge.
16
- */
17
- export declare function renderReviewStateBadge(state: ReviewState | undefined): RawHtml;
18
- /**
19
- * Iteration count for the entry's current stage. The sidecar's
20
- * `iterationByStage` records every stage the entry has touched; this
21
- * surfaces the count for the stage the entry is currently in. Defaults
22
- * to 0 when the bucket is missing (a brand-new entry on its first tick
23
- * before any iterate has fired).
24
- */
25
- export declare function iterationForCurrentStage(entry: Entry): number;
20
+ import type { Entry } from '@deskwork/core/schema/entry';
26
21
  /**
27
22
  * Build the per-row action strip. Affordances vary by stage:
28
23
  *
29
- * - Linear pipeline stages (Ideas / Planned / Outlining / Drafting /
30
- * Final): "open →" link to the review surface, plus an "iterate"
31
- * copy-CLI button when reviewState is `iterating` and an
32
- * "approve" copy-CLI button when reviewState is `approved`.
33
- * - Published: "view " (read-only review surface).
24
+ * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
25
+ * "open →" link, "iterate →" copy-CLI button (always; no state gate),
26
+ * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
27
+ * - Final: "open →", "approve" (graduates to Published; assigns a
28
+ * version per the operator's scheme), "cancel ". NO iterate
29
+ * (Final locks content per the spec).
30
+ * - Published: "view →" (read-only review surface). Future enhancement:
31
+ * surface a "revise" affordance that inducts back to Drafting.
34
32
  * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
35
33
  *
36
- * All non-terminal stages also get a `scrapbook ↗` link (#157) — the
37
- * scrapbook viewer is the primary surface for entry-attached research
38
- * notes / images / config / drafts and was previously unreachable
39
- * from the dashboard.
34
+ * All non-terminal stages also get a `scrapbook ↗` link (#157).
40
35
  *
41
36
  * Each button's behavior is parked behind a `data-copy` attribute so
42
37
  * the existing studio client (editorial-studio-client.ts) handles
@@ -1 +1 @@
1
- {"version":3,"file":"affordances.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAS,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAQ7E;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAK9E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAE7D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAkD3E"}
1
+ {"version":3,"file":"affordances.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,KAAK,EAAS,MAAM,6BAA6B,CAAC;AAEhE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAkE3E"}
@@ -6,49 +6,32 @@
6
6
  * carry a `data-copy` payload that the existing studio client copies
7
7
  * to the clipboard. No new backend handlers are wired here; the
8
8
  * universal-verb skills are the canonical action path.
9
+ *
10
+ * Per DESKWORK-STATE-MACHINE.md (v5):
11
+ * - Verbs are stage-gated, not state-gated. The iterate button shows
12
+ * on stages-that-permit-edits (Ideas/Planned/Outlining/Drafting),
13
+ * not on Final (locked) or Published (immutable).
14
+ * - Revisions (the iteration counter) are bookkeeping. They do not
15
+ * surface in routine UI; the operator only sees them via revision
16
+ * history / revert flows. The previous "iteration: N" per-row
17
+ * display has been removed.
9
18
  */
10
19
  import { html, unsafe } from "../html.js";
11
20
  import { scrapbookViewerUrl } from "../../components/scrapbook-item.js";
12
- const REVIEW_STATE_LABEL = {
13
- 'in-review': 'in review',
14
- iterating: 'iterating',
15
- approved: 'approved',
16
- };
17
- /**
18
- * Render the reviewState badge. When the entry has no reviewState
19
- * (most pre-review stages), render an em-dash placeholder so the row
20
- * stays grid-aligned with sibling rows that DO carry a badge.
21
- */
22
- export function renderReviewStateBadge(state) {
23
- if (state === undefined) {
24
- return unsafe('<span class="er-stamp er-stamp-none" data-review-state="none">—</span>');
25
- }
26
- return unsafe(html `<span class="er-stamp er-stamp-${state}" data-review-state="${state}">${REVIEW_STATE_LABEL[state]}</span>`);
27
- }
28
- /**
29
- * Iteration count for the entry's current stage. The sidecar's
30
- * `iterationByStage` records every stage the entry has touched; this
31
- * surfaces the count for the stage the entry is currently in. Defaults
32
- * to 0 when the bucket is missing (a brand-new entry on its first tick
33
- * before any iterate has fired).
34
- */
35
- export function iterationForCurrentStage(entry) {
36
- return entry.iterationByStage[entry.currentStage] ?? 0;
37
- }
38
21
  /**
39
22
  * Build the per-row action strip. Affordances vary by stage:
40
23
  *
41
- * - Linear pipeline stages (Ideas / Planned / Outlining / Drafting /
42
- * Final): "open →" link to the review surface, plus an "iterate"
43
- * copy-CLI button when reviewState is `iterating` and an
44
- * "approve" copy-CLI button when reviewState is `approved`.
45
- * - Published: "view " (read-only review surface).
24
+ * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
25
+ * "open →" link, "iterate →" copy-CLI button (always; no state gate),
26
+ * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
27
+ * - Final: "open →", "approve" (graduates to Published; assigns a
28
+ * version per the operator's scheme), "cancel ". NO iterate
29
+ * (Final locks content per the spec).
30
+ * - Published: "view →" (read-only review surface). Future enhancement:
31
+ * surface a "revise" affordance that inducts back to Drafting.
46
32
  * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
47
33
  *
48
- * All non-terminal stages also get a `scrapbook ↗` link (#157) — the
49
- * scrapbook viewer is the primary surface for entry-attached research
50
- * notes / images / config / drafts and was previously unreachable
51
- * from the dashboard.
34
+ * All non-terminal stages also get a `scrapbook ↗` link (#157).
52
35
  *
53
36
  * Each button's behavior is parked behind a `data-copy` attribute so
54
37
  * the existing studio client (editorial-studio-client.ts) handles
@@ -78,16 +61,32 @@ export function renderRowActions(entry, defaultSite) {
78
61
  if (isLinearActiveStage(stage)) {
79
62
  buttons.push(html `<a class="er-btn er-btn-small" href="${reviewLink}"
80
63
  title="open the review surface for ${entry.slug}">open →</a>`);
81
- if (entry.reviewState === 'iterating') {
64
+ // Iterate — stage-gated per DESKWORK-STATE-MACHINE.md Commandment II:
65
+ // verbs are stage-gated, never state-gated. Iterate runs on stages
66
+ // that permit edits (Ideas / Planned / Outlining / Drafting); Final
67
+ // locks content so iterate is hidden there. The previous
68
+ // `reviewState === 'iterating'` gate was a Commandment II violation;
69
+ // removed in the v0.19 spec-conformance sweep.
70
+ if (stagePermitsEdits(stage)) {
82
71
  buttons.push(html `<button class="er-btn er-btn-small er-btn-primary er-copy-btn" type="button"
83
72
  data-copy="/deskwork:iterate ${entry.slug}"
84
73
  title="operator clicked Iterate — run the iterate skill in Claude Code">iterate →</button>`);
85
74
  }
86
- if (entry.reviewState === 'approved') {
87
- buttons.push(html `<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
88
- data-copy="/deskwork:approve ${entry.slug}"
89
- title="approved graduate to the next stage">approve →</button>`);
90
- }
75
+ // Approve (#244) unconditional on active-pipeline rows. Mirrors
76
+ // the review-surface decision strip (Approve is always visible
77
+ // there); the dashboard previously gated this button on
78
+ // `reviewState === 'approved'`, which is a transient state most
79
+ // rows never carry, leaving the button effectively invisible. The
80
+ // operator should be able to advance any active-pipeline entry
81
+ // from the dashboard without first opening the review surface.
82
+ buttons.push(html `<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
83
+ data-copy="/deskwork:approve ${entry.slug}"
84
+ title="advance this entry to the next stage">approve →</button>`);
85
+ // Cancel (#242) — pull this entry off-pipeline. Same clipboard
86
+ // routing as approve / iterate; the skill mutates sidecar + journal.
87
+ buttons.push(html `<button class="er-btn er-btn-small er-btn-reject er-copy-btn" type="button"
88
+ data-copy="/deskwork:cancel ${entry.slug}"
89
+ title="pull this entry off-pipeline (Cancelled). Reversible via /deskwork:induct.">cancel ⊘</button>`);
91
90
  }
92
91
  else if (stage === 'Published') {
93
92
  buttons.push(html `<a class="er-btn er-btn-small" href="${reviewLink}"
@@ -111,4 +110,16 @@ function isLinearActiveStage(stage) {
111
110
  stage === 'Drafting' ||
112
111
  stage === 'Final');
113
112
  }
113
+ /**
114
+ * Stages that permit content edits (and therefore iterate). Final
115
+ * locks content per DESKWORK-STATE-MACHINE.md — iterate refuses there;
116
+ * the operator must induct backward to a stage that permits edits if
117
+ * they want to revise a Final entry.
118
+ */
119
+ function stagePermitsEdits(stage) {
120
+ return (stage === 'Ideas' ||
121
+ stage === 'Planned' ||
122
+ stage === 'Outlining' ||
123
+ stage === 'Drafting');
124
+ }
114
125
  //# sourceMappingURL=affordances.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"affordances.js","sourceRoot":"","sources":["../../../src/pages/dashboard/affordances.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,WAAmB;IAChE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC;IACjC,MAAM,UAAU,GAAG,+BAA+B,KAAK,CAAC,IAAI,EAAE,CAAC;IAC/D,qEAAqE;IACrE,qEAAqE;IACrE,qEAAqE;IACrE,oEAAoE;IACpE,kCAAkC;IAClC,EAAE;IACF,oEAAoE;IACpE,4DAA4D;IAC5D,sEAAsE;IACtE,oDAAoD;IACpD,kEAAkE;IAClE,gDAAgD;IAChD,MAAM,SAAS,GAAG,kBAAkB,CAAC;QACnC,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,OAAO,EAAE,KAAK,CAAC,IAAI;KACpB,CAAC,CAAC;IAEH,IAAI,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,wCAAwC,UAAU;2CAC5B,KAAK,CAAC,IAAI,cAAc,CAAC,CAAC;QACjE,sEAAsE;QACtE,mEAAmE;QACnE,oEAAoE;QACpE,yDAAyD;QACzD,qEAAqE;QACrE,+CAA+C;QAC/C,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;uCACgB,KAAK,CAAC,IAAI;mGACkD,CAAC,CAAC;QACjG,CAAC;QACD,kEAAkE;QAClE,+DAA+D;QAC/D,wDAAwD;QACxD,gEAAgE;QAChE,kEAAkE;QAClE,+DAA+D;QAC/D,+DAA+D;QAC/D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;qCACgB,KAAK,CAAC,IAAI;sEACuB,CAAC,CAAC;QACpE,+DAA+D;QAC/D,qEAAqE;QACrE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;oCACe,KAAK,CAAC,IAAI;2GAC6D,CAAC,CAAC;IAC3G,CAAC;SAAM,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA,wCAAwC,UAAU;0EACG,CAAC,CAAC;IAC1E,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;oCACe,KAAK,CAAC,IAAI;wEAC0B,CAAC,CAAC;IACxE,CAAC;IAED,uDAAuD;IACvD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAA;YACP,SAAS;sFACiE,CAAC,CAAC;IAEtF,OAAO,MAAM,CAAC,oCAAoC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAY;IACvC,OAAO,CACL,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,WAAW;QACrB,KAAK,KAAK,UAAU;QACpB,KAAK,KAAK,OAAO,CAClB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAY;IACrC,OAAO,CACL,KAAK,KAAK,OAAO;QACjB,KAAK,KAAK,SAAS;QACnB,KAAK,KAAK,WAAW;QACrB,KAAK,KAAK,UAAU,CACrB,CAAC;AACJ,CAAC"}
@@ -6,55 +6,35 @@
6
6
  * carry a `data-copy` payload that the existing studio client copies
7
7
  * to the clipboard. No new backend handlers are wired here; the
8
8
  * universal-verb skills are the canonical action path.
9
+ *
10
+ * Per DESKWORK-STATE-MACHINE.md (v5):
11
+ * - Verbs are stage-gated, not state-gated. The iterate button shows
12
+ * on stages-that-permit-edits (Ideas/Planned/Outlining/Drafting),
13
+ * not on Final (locked) or Published (immutable).
14
+ * - Revisions (the iteration counter) are bookkeeping. They do not
15
+ * surface in routine UI; the operator only sees them via revision
16
+ * history / revert flows. The previous "iteration: N" per-row
17
+ * display has been removed.
9
18
  */
10
19
 
11
20
  import { html, unsafe, type RawHtml } from '../html.ts';
12
21
  import { scrapbookViewerUrl } from '../../components/scrapbook-item.ts';
13
- import type { Entry, Stage, ReviewState } from '@deskwork/core/schema/entry';
14
-
15
- const REVIEW_STATE_LABEL: Record<ReviewState, string> = {
16
- 'in-review': 'in review',
17
- iterating: 'iterating',
18
- approved: 'approved',
19
- };
20
-
21
- /**
22
- * Render the reviewState badge. When the entry has no reviewState
23
- * (most pre-review stages), render an em-dash placeholder so the row
24
- * stays grid-aligned with sibling rows that DO carry a badge.
25
- */
26
- export function renderReviewStateBadge(state: ReviewState | undefined): RawHtml {
27
- if (state === undefined) {
28
- return unsafe('<span class="er-stamp er-stamp-none" data-review-state="none">—</span>');
29
- }
30
- return unsafe(html`<span class="er-stamp er-stamp-${state}" data-review-state="${state}">${REVIEW_STATE_LABEL[state]}</span>`);
31
- }
32
-
33
- /**
34
- * Iteration count for the entry's current stage. The sidecar's
35
- * `iterationByStage` records every stage the entry has touched; this
36
- * surfaces the count for the stage the entry is currently in. Defaults
37
- * to 0 when the bucket is missing (a brand-new entry on its first tick
38
- * before any iterate has fired).
39
- */
40
- export function iterationForCurrentStage(entry: Entry): number {
41
- return entry.iterationByStage[entry.currentStage] ?? 0;
42
- }
22
+ import type { Entry, Stage } from '@deskwork/core/schema/entry';
43
23
 
44
24
  /**
45
25
  * Build the per-row action strip. Affordances vary by stage:
46
26
  *
47
- * - Linear pipeline stages (Ideas / Planned / Outlining / Drafting /
48
- * Final): "open →" link to the review surface, plus an "iterate"
49
- * copy-CLI button when reviewState is `iterating` and an
50
- * "approve" copy-CLI button when reviewState is `approved`.
51
- * - Published: "view " (read-only review surface).
27
+ * - Stages-that-permit-edits (Ideas / Planned / Outlining / Drafting):
28
+ * "open →" link, "iterate →" copy-CLI button (always; no state gate),
29
+ * "approve →" copy-CLI button, "cancel ⊘" copy-CLI button.
30
+ * - Final: "open →", "approve" (graduates to Published; assigns a
31
+ * version per the operator's scheme), "cancel ". NO iterate
32
+ * (Final locks content per the spec).
33
+ * - Published: "view →" (read-only review surface). Future enhancement:
34
+ * surface a "revise" affordance that inducts back to Drafting.
52
35
  * - Blocked / Cancelled: "induct →" copy-CLI to bring the entry back.
53
36
  *
54
- * All non-terminal stages also get a `scrapbook ↗` link (#157) — the
55
- * scrapbook viewer is the primary surface for entry-attached research
56
- * notes / images / config / drafts and was previously unreachable
57
- * from the dashboard.
37
+ * All non-terminal stages also get a `scrapbook ↗` link (#157).
58
38
  *
59
39
  * Each button's behavior is parked behind a `data-copy` attribute so
60
40
  * the existing studio client (editorial-studio-client.ts) handles
@@ -85,16 +65,32 @@ export function renderRowActions(entry: Entry, defaultSite: string): RawHtml {
85
65
  if (isLinearActiveStage(stage)) {
86
66
  buttons.push(html`<a class="er-btn er-btn-small" href="${reviewLink}"
87
67
  title="open the review surface for ${entry.slug}">open →</a>`);
88
- if (entry.reviewState === 'iterating') {
68
+ // Iterate — stage-gated per DESKWORK-STATE-MACHINE.md Commandment II:
69
+ // verbs are stage-gated, never state-gated. Iterate runs on stages
70
+ // that permit edits (Ideas / Planned / Outlining / Drafting); Final
71
+ // locks content so iterate is hidden there. The previous
72
+ // `reviewState === 'iterating'` gate was a Commandment II violation;
73
+ // removed in the v0.19 spec-conformance sweep.
74
+ if (stagePermitsEdits(stage)) {
89
75
  buttons.push(html`<button class="er-btn er-btn-small er-btn-primary er-copy-btn" type="button"
90
76
  data-copy="/deskwork:iterate ${entry.slug}"
91
77
  title="operator clicked Iterate — run the iterate skill in Claude Code">iterate →</button>`);
92
78
  }
93
- if (entry.reviewState === 'approved') {
94
- buttons.push(html`<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
95
- data-copy="/deskwork:approve ${entry.slug}"
96
- title="approved graduate to the next stage">approve →</button>`);
97
- }
79
+ // Approve (#244) unconditional on active-pipeline rows. Mirrors
80
+ // the review-surface decision strip (Approve is always visible
81
+ // there); the dashboard previously gated this button on
82
+ // `reviewState === 'approved'`, which is a transient state most
83
+ // rows never carry, leaving the button effectively invisible. The
84
+ // operator should be able to advance any active-pipeline entry
85
+ // from the dashboard without first opening the review surface.
86
+ buttons.push(html`<button class="er-btn er-btn-small er-btn-approve er-copy-btn" type="button"
87
+ data-copy="/deskwork:approve ${entry.slug}"
88
+ title="advance this entry to the next stage">approve →</button>`);
89
+ // Cancel (#242) — pull this entry off-pipeline. Same clipboard
90
+ // routing as approve / iterate; the skill mutates sidecar + journal.
91
+ buttons.push(html`<button class="er-btn er-btn-small er-btn-reject er-copy-btn" type="button"
92
+ data-copy="/deskwork:cancel ${entry.slug}"
93
+ title="pull this entry off-pipeline (Cancelled). Reversible via /deskwork:induct.">cancel ⊘</button>`);
98
94
  } else if (stage === 'Published') {
99
95
  buttons.push(html`<a class="er-btn er-btn-small" href="${reviewLink}"
100
96
  title="read-only review surface for the published entry">view →</a>`);
@@ -121,3 +117,18 @@ function isLinearActiveStage(stage: Stage): boolean {
121
117
  stage === 'Final'
122
118
  );
123
119
  }
120
+
121
+ /**
122
+ * Stages that permit content edits (and therefore iterate). Final
123
+ * locks content per DESKWORK-STATE-MACHINE.md — iterate refuses there;
124
+ * the operator must induct backward to a stage that permits edits if
125
+ * they want to revise a Final entry.
126
+ */
127
+ function stagePermitsEdits(stage: Stage): boolean {
128
+ return (
129
+ stage === 'Ideas' ||
130
+ stage === 'Planned' ||
131
+ stage === 'Outlining' ||
132
+ stage === 'Drafting'
133
+ );
134
+ }
@@ -2,9 +2,15 @@
2
2
  * Dashboard masthead + filter strip.
3
3
  *
4
4
  * Pipeline-redesign Task 34. The masthead reads from sidecar-derived
5
- * counts (total entries, in-review entries) instead of the legacy
6
- * workflow store. The filter strip exposes one chip per stage so
7
- * operators can collapse to a single section quickly.
5
+ * counts (total entries) instead of the legacy workflow store. The
6
+ * filter strip is a search-only row; stage chips were removed in v0.19
7
+ * (they were never used and added chrome noise). The collapsible stage
8
+ * tiles on mobile now serve the per-stage navigation role chips used to.
9
+ *
10
+ * Review-state-derived stats ("X in review", "X approved") were removed
11
+ * in v0.19 per operator: review state isn't user-facing data and is
12
+ * slated for backend removal. The masthead surfaces only stage-shape
13
+ * counts (date + total) now.
8
14
  */
9
15
  import type { DashboardData } from './data.ts';
10
16
  import { type RawHtml } from '../html.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/header.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAwBxD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,aAAa,EACnB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,IAAI,GACR,OAAO,CA4BT;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAa3C"}
1
+ {"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAQxD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,aAAa,EACnB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,IAAI,GACR,OAAO,CAwBT;AAED,wBAAgB,iBAAiB,IAAI,OAAO,CAM3C"}
@@ -2,39 +2,28 @@
2
2
  * Dashboard masthead + filter strip.
3
3
  *
4
4
  * Pipeline-redesign Task 34. The masthead reads from sidecar-derived
5
- * counts (total entries, in-review entries) instead of the legacy
6
- * workflow store. The filter strip exposes one chip per stage so
7
- * operators can collapse to a single section quickly.
5
+ * counts (total entries) instead of the legacy workflow store. The
6
+ * filter strip is a search-only row; stage chips were removed in v0.19
7
+ * (they were never used and added chrome noise). The collapsible stage
8
+ * tiles on mobile now serve the per-stage navigation role chips used to.
9
+ *
10
+ * Review-state-derived stats ("X in review", "X approved") were removed
11
+ * in v0.19 per operator: review state isn't user-facing data and is
12
+ * slated for backend removal. The masthead surfaces only stage-shape
13
+ * counts (date + total) now.
8
14
  */
9
- import { DASHBOARD_STAGE_ORDER } from "./data.js";
10
15
  import { html, unsafe } from "../html.js";
11
16
  import { getStudioVersion } from "../../lib/version.js";
12
17
  const MONTH_NAMES = [
13
18
  'January', 'February', 'March', 'April', 'May', 'June',
14
19
  'July', 'August', 'September', 'October', 'November', 'December',
15
20
  ];
16
- function reviewActiveCount(data) {
17
- let n = 0;
18
- for (const entry of data.entries) {
19
- if (entry.reviewState === 'in-review' || entry.reviewState === 'iterating')
20
- n++;
21
- }
22
- return n;
23
- }
24
- function approvedCount(data) {
25
- let n = 0;
26
- for (const entry of data.entries) {
27
- if (entry.reviewState === 'approved')
28
- n++;
29
- }
30
- return n;
31
- }
32
21
  export function renderHeader(data, projectRoot, now) {
33
22
  const volume = '01';
34
23
  const issueNum = String(data.entries.length).padStart(2, '0');
35
24
  const issueDate = `${now.getDate()} ${MONTH_NAMES[now.getMonth()]} ${now.getFullYear()}`;
36
25
  return unsafe(html `
37
- <header class="er-pagehead er-pagehead--centered">
26
+ <header class="er-pagehead er-pagehead--centered er-pagehead--dashboard">
38
27
  <p class="er-pagehead__kicker">
39
28
  Vol. ${volume} &middot; № ${issueNum}
40
29
  </p>
@@ -51,10 +40,6 @@ export function renderHeader(data, projectRoot, now) {
51
40
  <span>${issueDate}</span>
52
41
  <span class="sep">·</span>
53
42
  <span>${data.entries.length} on the calendar</span>
54
- <span class="sep">·</span>
55
- <span>${reviewActiveCount(data)} in review</span>
56
- <span class="sep">·</span>
57
- <span>${approvedCount(data)} approved</span>
58
43
  </p>
59
44
  </header>`);
60
45
  }
@@ -63,11 +48,6 @@ export function renderFilterStrip() {
63
48
  <section class="er-filter" data-filter-strip>
64
49
  <span class="er-filter-label">Find</span>
65
50
  <input type="search" data-filter-input placeholder="slug, title…" autocomplete="off" />
66
- <span class="er-filter-label er-filter-label--gap">Stage</span>
67
- <div class="er-chips" role="tablist">
68
- <button class="er-chip" aria-pressed="true" data-stage-chip="all">all</button>
69
- ${DASHBOARD_STAGE_ORDER.map((s) => unsafe(html `<button class="er-chip" data-stage-chip="${s}">${s.toLowerCase()}</button>`))}
70
- </div>
71
51
  </section>`);
72
52
  }
73
53
  //# sourceMappingURL=header.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"header.js","sourceRoot":"","sources":["../../../src/pages/dashboard/header.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,GAAG;IAClB,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;IACtD,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;CACjE,CAAC;AAEF,SAAS,iBAAiB,CAAC,IAAmB;IAC5C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW,IAAI,KAAK,CAAC,WAAW,KAAK,WAAW;YAAE,CAAC,EAAE,CAAC;IAClF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,aAAa,CAAC,IAAmB;IACxC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,WAAW,KAAK,UAAU;YAAE,CAAC,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAmB,EACnB,WAAmB,EACnB,GAAS;IAET,MAAM,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;IACzF,OAAO,MAAM,CAAC,IAAI,CAAA;;;aAGP,MAAM,eAAe,QAAQ;;;;;;uBAMnB,WAAW;;;4CAGU,gBAAgB,EAAE;;;cAGhD,SAAS;;cAET,IAAI,CAAC,OAAO,CAAC,MAAM;;cAEnB,iBAAiB,CAAC,IAAI,CAAC;;cAEvB,aAAa,CAAC,IAAI,CAAC;;YAErB,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;;;;UAOV,qBAAqB,CAAC,GAAG,CACzB,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAA,4CAA4C,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,WAAW,CAAC,CAChG;;eAEM,CAAC,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"header.js","sourceRoot":"","sources":["../../../src/pages/dashboard/header.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,EAAgB,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,GAAG;IAClB,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM;IACtD,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU;CACjE,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,IAAmB,EACnB,WAAmB,EACnB,GAAS;IAET,MAAM,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC9D,MAAM,SAAS,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;IACzF,OAAO,MAAM,CAAC,IAAI,CAAA;;;aAGP,MAAM,eAAe,QAAQ;;;;;;uBAMnB,WAAW;;;4CAGU,gBAAgB,EAAE;;;cAGhD,SAAS;;cAET,IAAI,CAAC,OAAO,CAAC,MAAM;;YAErB,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAA;;;;eAIL,CAAC,CAAC;AACjB,CAAC"}
@@ -2,13 +2,18 @@
2
2
  * Dashboard masthead + filter strip.
3
3
  *
4
4
  * Pipeline-redesign Task 34. The masthead reads from sidecar-derived
5
- * counts (total entries, in-review entries) instead of the legacy
6
- * workflow store. The filter strip exposes one chip per stage so
7
- * operators can collapse to a single section quickly.
5
+ * counts (total entries) instead of the legacy workflow store. The
6
+ * filter strip is a search-only row; stage chips were removed in v0.19
7
+ * (they were never used and added chrome noise). The collapsible stage
8
+ * tiles on mobile now serve the per-stage navigation role chips used to.
9
+ *
10
+ * Review-state-derived stats ("X in review", "X approved") were removed
11
+ * in v0.19 per operator: review state isn't user-facing data and is
12
+ * slated for backend removal. The masthead surfaces only stage-shape
13
+ * counts (date + total) now.
8
14
  */
9
15
 
10
16
  import type { DashboardData } from './data.ts';
11
- import { DASHBOARD_STAGE_ORDER } from './data.ts';
12
17
  import { html, unsafe, type RawHtml } from '../html.ts';
13
18
  import { getStudioVersion } from '../../lib/version.ts';
14
19
 
@@ -17,22 +22,6 @@ const MONTH_NAMES = [
17
22
  'July', 'August', 'September', 'October', 'November', 'December',
18
23
  ];
19
24
 
20
- function reviewActiveCount(data: DashboardData): number {
21
- let n = 0;
22
- for (const entry of data.entries) {
23
- if (entry.reviewState === 'in-review' || entry.reviewState === 'iterating') n++;
24
- }
25
- return n;
26
- }
27
-
28
- function approvedCount(data: DashboardData): number {
29
- let n = 0;
30
- for (const entry of data.entries) {
31
- if (entry.reviewState === 'approved') n++;
32
- }
33
- return n;
34
- }
35
-
36
25
  export function renderHeader(
37
26
  data: DashboardData,
38
27
  projectRoot: string,
@@ -42,7 +31,7 @@ export function renderHeader(
42
31
  const issueNum = String(data.entries.length).padStart(2, '0');
43
32
  const issueDate = `${now.getDate()} ${MONTH_NAMES[now.getMonth()]} ${now.getFullYear()}`;
44
33
  return unsafe(html`
45
- <header class="er-pagehead er-pagehead--centered">
34
+ <header class="er-pagehead er-pagehead--centered er-pagehead--dashboard">
46
35
  <p class="er-pagehead__kicker">
47
36
  Vol. ${volume} &middot; № ${issueNum}
48
37
  </p>
@@ -59,10 +48,6 @@ export function renderHeader(
59
48
  <span>${issueDate}</span>
60
49
  <span class="sep">·</span>
61
50
  <span>${data.entries.length} on the calendar</span>
62
- <span class="sep">·</span>
63
- <span>${reviewActiveCount(data)} in review</span>
64
- <span class="sep">·</span>
65
- <span>${approvedCount(data)} approved</span>
66
51
  </p>
67
52
  </header>`);
68
53
  }
@@ -72,12 +57,5 @@ export function renderFilterStrip(): RawHtml {
72
57
  <section class="er-filter" data-filter-strip>
73
58
  <span class="er-filter-label">Find</span>
74
59
  <input type="search" data-filter-input placeholder="slug, title…" autocomplete="off" />
75
- <span class="er-filter-label er-filter-label--gap">Stage</span>
76
- <div class="er-chips" role="tablist">
77
- <button class="er-chip" aria-pressed="true" data-stage-chip="all">all</button>
78
- ${DASHBOARD_STAGE_ORDER.map(
79
- (s) => unsafe(html`<button class="er-chip" data-stage-chip="${s}">${s.toLowerCase()}</button>`),
80
- )}
81
- </div>
82
60
  </section>`);
83
61
  }
@@ -1,12 +1,17 @@
1
1
  /**
2
2
  * Single-stage section renderer.
3
3
  *
4
- * Pipeline-redesign Task 34. Each of the eight stage sections renders
5
- * with a section heading (stage name + entry count) and either a list
6
- * of rows or an empty-state placeholder. Per-row HTML carries the
7
- * sidecar-derived state inline (iteration count + reviewState badge)
8
- * so an operator can see at a glance where each entry sits without
9
- * opening it.
4
+ * Each of the eight stage sections (plus the Distribution placeholder)
5
+ * renders with a section heading (stage name + entry count) and either
6
+ * a list of rows or an empty-state placeholder. Each row carries the
7
+ * entry's slug, title, updated-at timestamp, and stage-gated verb
8
+ * buttons. Per DESKWORK-STATE-MACHINE.md Commandment III, rows do NOT
9
+ * surface iteration counts or reviewState — those were retired in
10
+ * v0.19 along with the legacy reviewState concept.
11
+ *
12
+ * On mobile, each section is fronted by a collapsible tile (see
13
+ * `renderStageTile`); on desktop the tiles are display:none and the
14
+ * `<h2 class="er-section-head">` heading carries the stage name.
10
15
  */
11
16
  import { type RawHtml } from '../html.ts';
12
17
  import type { Entry, Stage } from '@deskwork/core/schema/entry';
@@ -14,27 +19,49 @@ import type { Entry, Stage } from '@deskwork/core/schema/entry';
14
19
  * Render one entry as a single dashboard row. Carries inline:
15
20
  * - slug (linked to the review surface)
16
21
  * - title
17
- * - iteration count for the entry's currentStage
18
- * - reviewState badge (or an em-dash placeholder)
19
22
  * - updatedAt timestamp
20
23
  * - per-stage action buttons
24
+ *
25
+ * Per DESKWORK-STATE-MACHINE.md (v5): revisions (the iteration counter)
26
+ * are bookkeeping and do NOT surface in routine UI. The previous
27
+ * "iteration: N" inline display was a violation — operators see
28
+ * revisions only via the View History surface and revert flows.
29
+ * reviewState badges are likewise retired (Commandment III).
21
30
  */
22
31
  export declare function renderRow(entry: Entry, index: number, defaultSite: string): RawHtml;
23
32
  /**
24
33
  * Render one full stage section: heading + ornaments + count + rows.
25
34
  *
26
- * Empty stages render compact (just the heading, no placeholder body)
27
- * keeps the operator's sense of pipeline shape without padding the
28
- * dashboard with multi-line empty placeholders for low-volume
35
+ * The output is wrapped in a `.er-stage-block` div that pairs a mobile-
36
+ * only stage tile (the collapsible head) with the existing section. On
37
+ * desktop, the tile is `display: none` and the section's `<h2>` head
38
+ * carries the heading as before. On mobile, the section's head is hidden
39
+ * and the tile is shown; tapping the tile toggles a `data-collapsed`
40
+ * attribute on the section that hides/shows its rows. Single-expand
41
+ * (tapping one tile collapses the others) is handled by
42
+ * `dashboard/stage-tiles.ts`.
43
+ *
44
+ * Empty stages still render their tile (so the pipeline shape is visible
45
+ * at-rest on phone) but the empty section body itself is hidden on mobile.
46
+ *
47
+ * Empty stages on desktop render compact (just the heading, no placeholder
48
+ * body) — keeps the operator's sense of pipeline shape without padding
49
+ * the dashboard with multi-line empty placeholders for low-volume
29
50
  * calendars (#112). The hover title still surfaces the stage's
30
51
  * "what to run next" hint when the operator points at the heading.
31
52
  */
32
53
  export declare function renderStageSection(stage: Stage, entries: readonly Entry[], defaultSite: string): RawHtml;
33
54
  /**
34
- * Render the reserved Distribution placeholder. Stays a separate
35
- * sibling of the stage sections distribution records (shortform
36
- * cross-posts) are tracked under their own model and the dashboard
37
- * surfaces only a placeholder here until that integration lands.
55
+ * Render the reserved Distribution placeholder. Distribution isn't a
56
+ * pipeline stage in the formal sense (no entries flow through it; it
57
+ * lives under its own model when shortform cross-posts arrive), but on
58
+ * the mobile dashboard it renders as a stage tile alongside the rest
59
+ * so the operator's pipeline-shape scan stays uniform — see operator
60
+ * feedback on 2026-05-09. The tile is `is-empty` + `disabled` until
61
+ * DistributionRecords land in the data layer.
62
+ *
63
+ * On desktop, the existing section + heading + placeholder text render
64
+ * as before; the tile is `display: none` per dashboard-mobile.css.
38
65
  */
39
66
  export declare function renderDistributionPlaceholder(): RawHtml;
40
67
  //# sourceMappingURL=section.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AA6BhE;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAgCnF;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CA0BT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAWvD"}
1
+ {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAgB,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAyBhE;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CA2BnF;AAgCD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,SAAS,KAAK,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,OAAO,CAkCT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAsBvD"}