domma-cms 1.6.59 → 1.7.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 (143) hide show
  1. package/CHANGELOG.md +4344 -0
  2. package/README.md +1 -1
  3. package/admin/dist/domma/domma-tools.css +3 -3
  4. package/admin/dist/domma/domma-tools.min.js +3 -3
  5. package/admin/js/api.js +1 -1
  6. package/admin/js/app.js +2 -2
  7. package/admin/js/lib/draft-owner.js +1 -0
  8. package/admin/js/lib/effect-defs.js +1 -1
  9. package/admin/js/lib/effects-builder.js +2 -2
  10. package/admin/js/lib/page-editor-reference.js +5 -5
  11. package/admin/js/lib/shortcode-tags.js +1 -1
  12. package/admin/js/templates/docs/usage-shortcodes.html +39 -0
  13. package/admin/js/views/user-editor.js +1 -1
  14. package/docs/DommaFeatures.md +3005 -0
  15. package/docs/MultiTenant.md +176 -0
  16. package/docs/api-reference.md +1667 -0
  17. package/docs/cache.md +96 -0
  18. package/docs/configuration.md +1811 -0
  19. package/docs/editions-and-licences.md +190 -0
  20. package/docs/getting-started.md +201 -0
  21. package/docs/guides/form-triggers.md +260 -0
  22. package/docs/guides/mongodb-storage-adapter.md +282 -0
  23. package/docs/guides/multi-page-forms.md +121 -0
  24. package/docs/images/scribe-composer.png +0 -0
  25. package/docs/markdown-shortcodes.md +1738 -0
  26. package/docs/pentest-report-2026-04-03.md +181 -0
  27. package/docs/plans/2026-02-28-admin-topbar-login-forms.md +349 -0
  28. package/docs/plans/2026-02-28-domma-ui-polish.md +286 -0
  29. package/docs/plans/2026-02-28-reset-seed-fresh-commands.md +520 -0
  30. package/docs/plans/2026-03-02-cookie-consent-design.md +86 -0
  31. package/docs/plans/2026-03-02-cookie-consent-plugin.md +453 -0
  32. package/docs/plans/2026-03-02-tooltip-sweep-and-back-to-top-plugin-design.md +126 -0
  33. package/docs/plans/2026-03-02-tooltip-sweep-back-to-top.md +427 -0
  34. package/docs/plans/2026-03-05-cookie-consent-btt-core.md +115 -0
  35. package/docs/plans/2026-03-05-custom-css-migrate-to-core-design.md +35 -0
  36. package/docs/plans/2026-03-05-custom-css-migrate-to-core.md +352 -0
  37. package/docs/plans/2026-03-05-scribe-script-shortcode.md +373 -0
  38. package/docs/plans/2026-03-05-user-types-design.md +139 -0
  39. package/docs/plans/2026-03-05-user-types-implementation.md +1035 -0
  40. package/docs/plans/2026-03-09-page-editor-view-cta-inserts-design.md +78 -0
  41. package/docs/plans/2026-03-09-page-editor-view-cta-inserts.md +388 -0
  42. package/docs/plans/2026-03-09-pro-documentation-design.md +80 -0
  43. package/docs/plans/2026-03-09-pro-documentation.md +1017 -0
  44. package/docs/plans/2026-06-10-core-project-design.md +240 -0
  45. package/docs/plugin-development.md +827 -0
  46. package/docs/recruitment-recipe.md +501 -0
  47. package/docs/scaffolding.md +312 -0
  48. package/docs/screenshots/calculator-floating.png +0 -0
  49. package/docs/screenshots/calculator-standard.png +0 -0
  50. package/docs/screenshots/email-settings.png +0 -0
  51. package/docs/screenshots/messages-count.png +0 -0
  52. package/docs/structure/user-types.md +107 -0
  53. package/docs/superpowers/plans/2026-05-25-admin-sidebar-via-menus.md +1112 -0
  54. package/docs/superpowers/plans/2026-06-08-navbar-mobile-drawer-and-menu-enrichment.md +1161 -0
  55. package/docs/superpowers/plans/2026-06-25-domma-docs-project.md +695 -0
  56. package/docs/superpowers/plans/2026-06-26-surveys-HANDOFF.md +68 -0
  57. package/docs/superpowers/plans/2026-06-26-surveys-pro-plugin.md +1902 -0
  58. package/docs/superpowers/plans/2026-08-19-collection-context-sort-export.md +1577 -0
  59. package/docs/superpowers/plans/2026-10-09-content-api.md +1192 -0
  60. package/docs/superpowers/specs/2026-03-12-form-followup-actions-design.md +152 -0
  61. package/docs/superpowers/specs/2026-03-12-page-editor-form-insert-and-per-page-theme-design.md +115 -0
  62. package/docs/superpowers/specs/2026-03-17-nav-hidden-items-design.md +85 -0
  63. package/docs/superpowers/specs/2026-03-19-accordion-insert-design.md +175 -0
  64. package/docs/superpowers/specs/2026-03-25-static-block-shortcode-design.md +153 -0
  65. package/docs/superpowers/specs/2026-03-25-text-shortcode-design.md +168 -0
  66. package/docs/superpowers/specs/2026-04-05-card-builder-design.md +315 -0
  67. package/docs/superpowers/specs/2026-04-06-insert-builders-design.md +278 -0
  68. package/docs/superpowers/specs/2026-04-06-layouts-design.md +226 -0
  69. package/docs/superpowers/specs/2026-04-07-blog-plugin-design.md +300 -0
  70. package/docs/superpowers/specs/2026-04-07-calendar-plugin-design.md +538 -0
  71. package/docs/superpowers/specs/2026-04-17-components-area-design.md +368 -0
  72. package/docs/superpowers/specs/2026-05-02-effects-slideover-overhaul-design.md +193 -0
  73. package/docs/superpowers/specs/2026-05-06-dashboard-rebuild-design.md +257 -0
  74. package/docs/superpowers/specs/2026-05-24-menus-design.md +466 -0
  75. package/docs/superpowers/specs/2026-05-25-admin-sidebar-via-menus-design.md +358 -0
  76. package/docs/superpowers/specs/2026-05-25-projects-design.md +380 -0
  77. package/docs/superpowers/specs/2026-06-08-navbar-mobile-drawer-and-menu-enrichment-design.md +292 -0
  78. package/docs/superpowers/specs/2026-06-08-sidebar-tools-plugins-folders-design.md +59 -0
  79. package/docs/superpowers/specs/2026-06-25-domma-docs-project-design.md +192 -0
  80. package/docs/superpowers/specs/2026-06-26-domma-charts-upstream-proposal.md +44 -0
  81. package/docs/superpowers/specs/2026-06-26-manager-scheduler-upstream-proposal.md +46 -0
  82. package/docs/superpowers/specs/2026-06-26-surveys-pro-plugin-design.md +206 -0
  83. package/docs/superpowers/specs/2026-07-02-shortcode-context-menu-design.md +96 -0
  84. package/docs/superpowers/specs/2026-08-19-collection-context-sort-export-design.md +330 -0
  85. package/docs/superpowers/specs/2026-09-22-dcms-marketplace-design.md +1150 -0
  86. package/docs/superpowers/specs/2026-10-09-content-api-design.md +325 -0
  87. package/docs/superpowers/specs/plans/2026-03-12-form-followup-actions.md +624 -0
  88. package/docs/superpowers/specs/plans/2026-03-12-page-editor-form-insert-and-per-page-theme.md +125 -0
  89. package/docs/superpowers/specs/plans/2026-03-17-nav-hidden-items.md +578 -0
  90. package/docs/superpowers/specs/plans/2026-03-19-accordion-insert.md +635 -0
  91. package/docs/superpowers/specs/plans/2026-03-25-text-shortcode.md +545 -0
  92. package/docs/superpowers/specs/plans/2026-04-05-card-builder.md +1970 -0
  93. package/docs/superpowers/specs/plans/2026-04-06-insert-builders.md +1049 -0
  94. package/docs/superpowers/specs/plans/2026-04-06-layouts.md +1015 -0
  95. package/docs/superpowers/specs/plans/2026-04-07-calendar-plugin.md +1526 -0
  96. package/docs/superpowers/specs/plans/2026-04-08-plugin-monetisation-split.md +242 -0
  97. package/docs/superpowers/specs/plans/2026-04-17-components-area.md +2038 -0
  98. package/docs/superpowers/specs/plans/2026-05-02-effects-slideover-overhaul.md +2335 -0
  99. package/docs/superpowers/specs/plans/2026-05-06-dashboard-rebuild.md +1999 -0
  100. package/docs/superpowers/specs/plans/2026-05-17-cache-system.md +1436 -0
  101. package/docs/superpowers/specs/plans/2026-05-24-menus.md +3096 -0
  102. package/docs/superpowers/specs/plans/2026-05-25-projects.md +2869 -0
  103. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step2-consolidation.md +505 -0
  104. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step3-catalogue-and-key.md +154 -0
  105. package/docs/superpowers/specs/plans/2026-09-22-tools-promotion.md +260 -0
  106. package/docs/theming.md +320 -0
  107. package/package.json +2 -2
  108. package/plugins/_lib/admin/mail/keyboard.js +49 -0
  109. package/plugins/_lib/admin/mail/reader-view.js +4 -2
  110. package/public/js/celebrations/core/canvas.js +1 -1
  111. package/public/js/celebrations/index.js +1 -1
  112. package/public/js/celebrations/licenses/ABeeZee-Regular-OFL.txt +93 -0
  113. package/public/js/celebrations/licenses/Allura-Regular-OFL.txt +93 -0
  114. package/public/js/celebrations/message-attrs.mjs +1 -0
  115. package/public/js/celebrations/themes/anniversary.js +1 -0
  116. package/public/js/celebrations/themes/autumn.js +1 -0
  117. package/public/js/celebrations/themes/birthday.js +1 -0
  118. package/public/js/celebrations/themes/butterfly-flight.js +1 -0
  119. package/public/js/celebrations/themes/calendar.js +1 -0
  120. package/public/js/celebrations/themes/chinese-new-year-dates.js +1 -0
  121. package/public/js/celebrations/themes/chinese-new-year.js +1 -0
  122. package/public/js/celebrations/themes/christmas.js +1 -1
  123. package/public/js/celebrations/themes/easter.js +1 -0
  124. package/public/js/celebrations/themes/garden-drawing.js +1 -0
  125. package/public/js/celebrations/themes/garden.js +1 -0
  126. package/public/js/celebrations/themes/graduation.js +1 -0
  127. package/public/js/celebrations/themes/greeting.js +1 -0
  128. package/public/js/celebrations/themes/make-it-rain.js +1 -0
  129. package/public/js/celebrations/themes/money-rain.js +1 -0
  130. package/public/js/celebrations/themes/new-year.js +1 -0
  131. package/public/js/celebrations/themes/occasion-drawing.js +1 -0
  132. package/public/js/celebrations/themes/occasions.js +1 -0
  133. package/public/js/celebrations/themes/rain-control.js +1 -0
  134. package/public/js/celebrations/themes/sparkler-font-data.js +1 -0
  135. package/public/js/celebrations/themes/sparkler-font.js +1 -0
  136. package/public/js/celebrations/themes/sparkler-writing.js +1 -0
  137. package/public/js/celebrations/themes/summer-garden.js +1 -0
  138. package/public/js/celebrations/themes/winter.js +1 -0
  139. package/public/js/celebrations/trait-data.mjs +1 -1
  140. package/public/js/effects.js +1 -1
  141. package/scripts/build.js +4 -0
  142. package/server/services/markdown.js +5 -2
  143. package/server/templates/page.html +1 -1
@@ -0,0 +1,78 @@
1
+ # Page Editor - View & CTA Insert Pickers Design
2
+
3
+ **Date:** 2026-03-09
4
+ **Status:** Approved
5
+
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Add **View** and **CTA** items to the Insert dropdown in the page editor toolbar. Each opens a guided picker dropdown that fetches live data from the API and generates the correct shortcode.
11
+
12
+ ---
13
+
14
+ ## Toolbar Changes
15
+
16
+ Two new items appended to the existing Insert dropdown (`plus-circle`) in `markdown-toolbar.js`:
17
+
18
+ | Label | Icon | Action key |
19
+ |-------|------|------------|
20
+ | View | `eye` | `view` |
21
+ | CTA | `mouse-pointer` | `cta` |
22
+
23
+ Both follow the established picker pattern (`openIconPicker`, `openSpacerPicker`): DOM-built dropdown, positioned below the trigger button, closed on outside click.
24
+
25
+ ---
26
+
27
+ ## View Picker
28
+
29
+ Fetches `GET /api/views` and presents:
30
+
31
+ 1. **View** - `<select>` populated with view slugs + titles from the API
32
+ 2. **Display** - `<select>`: Table / Cards / List
33
+ 3. **Insert** button → generates:
34
+
35
+ ```
36
+ [view slug="selected-slug" display="table" /]
37
+ ```
38
+
39
+ If the API returns no views, shows: *"No Views configured yet - create one under Data → Views."*
40
+
41
+ ---
42
+
43
+ ## CTA Picker
44
+
45
+ Fetches `GET /api/actions` and presents:
46
+
47
+ 1. **Action** - `<select>` populated with action slugs + titles
48
+ 2. **Label** - text input (pre-filled with the selected action's trigger label)
49
+ 3. **Entry ID** - free-text input (UUID), left blank by default with placeholder `"Paste entry UUID…"`
50
+ 4. **Style** - `<select>`: Primary / Secondary / Ghost / Danger
51
+ 5. **Icon** - text input (icon name, optional)
52
+ 6. **Confirm** - text input (optional confirmation message)
53
+ 7. **Insert** button → generates:
54
+
55
+ ```
56
+ [cta action="selected-action" entry="uuid-or-blank" style="primary" icon="check" confirm="Are you sure?"]Label[/cta]
57
+ ```
58
+
59
+ If no icon or confirm, those attributes are omitted. If entry ID is blank, `entry=""` is inserted so the author knows to fill it in.
60
+
61
+ If the API returns no actions, shows: *"No Actions configured yet - create one under Data → Actions."*
62
+
63
+ ---
64
+
65
+ ## Wiring
66
+
67
+ `markdown-toolbar.js` exports two new handler hooks: `onView(cb)` and `onCta(cb)`.
68
+
69
+ `page-editor.js` sets these handlers with the API fetch calls (same pattern as the existing `onCollection` handler).
70
+
71
+ ---
72
+
73
+ ## Files
74
+
75
+ | File | Change |
76
+ |------|--------|
77
+ | `admin/js/lib/markdown-toolbar.js` | Add `openViewPicker`, `openCtaPicker`, two Insert items, two handler hooks |
78
+ | `admin/js/views/page-editor.js` | Wire `toolbar.onView()` and `toolbar.onCta()` |
@@ -0,0 +1,388 @@
1
+ # Page Editor View & CTA Insert Pickers Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Add View and CTA shortcode insert pickers to the page editor toolbar's Insert dropdown.
6
+
7
+ **Architecture:** Two new items in the existing Insert dropdown call handler callbacks registered by page-editor.js. Each handler opens an `E.modal` with a DOM-built form, fetches the relevant API list, and inserts the generated shortcode via `insertAtCursor`. Exactly mirrors the existing `onCollection` pattern.
8
+
9
+ **Tech Stack:** Domma admin SPA, `E.modal` (light DOM projection), `insertAtCursor`, `api.views.list()`, `api.actions.list()`.
10
+
11
+ ---
12
+
13
+ ## Key reference points before starting
14
+
15
+ - **Insert dropdown items array** - `admin/js/lib/markdown-toolbar.js` line ~632-641 (inside `buttons` array, the `plus-circle` dropdown `items`)
16
+ - **`handlers` object** - line ~656: `const handlers = {link, image, card, grid, help, effects, collection}`
17
+ - **`executeAction`** - line ~523, the `else if (action === 'collection')` block ends at ~592
18
+ - **Return object** - line ~785, exports `onLink`, `onImage`, `onCard`, `onGrid`, `onHelp`, `onEffects`, `onCollection`
19
+ - **`onCollection` handler in page-editor.js** - line ~740-911, the exact modal pattern to follow
20
+ - **`labelStyle` / `inputStyle`** constants are defined inside `toolbar.onCollection` - redeclare them in each new handler (they are local constants, not exported)
21
+
22
+ ---
23
+
24
+ ## Task 1: Extend markdown-toolbar.js - add View and CTA hooks
25
+
26
+ **Files:**
27
+ - Modify: `admin/js/lib/markdown-toolbar.js`
28
+
29
+ **Step 1: Add `view` and `cta` to the `handlers` object**
30
+
31
+ Find (line ~656):
32
+ ```js
33
+ const handlers = {link: null, image: null, card: null, grid: null, help: null, effects: null, collection: null};
34
+ ```
35
+
36
+ Replace with:
37
+ ```js
38
+ const handlers = {link: null, image: null, card: null, grid: null, help: null, effects: null, collection: null, view: null, cta: null};
39
+ ```
40
+
41
+ **Step 2: Add two items to the Insert dropdown**
42
+
43
+ Find the Insert dropdown items array (the `plus-circle` button object, line ~632):
44
+ ```js
45
+ {label: 'Collection', icon: 'database', action: 'collection'},
46
+ ]
47
+ },
48
+ ```
49
+
50
+ Replace with:
51
+ ```js
52
+ {label: 'Collection', icon: 'database', action: 'collection'},
53
+ {label: 'View', icon: 'eye', action: 'view'},
54
+ {label: 'CTA Button', icon: 'mouse-pointer', action: 'cta'},
55
+ ]
56
+ },
57
+ ```
58
+
59
+ **Step 3: Add `view` and `cta` branches to `executeAction`**
60
+
61
+ Find (immediately after the `collection` block, line ~591-593):
62
+ ```js
63
+ } else if (action === 'help') {
64
+ if (handlers.help) handlers.help(ta);
65
+ }
66
+ ```
67
+
68
+ Replace with:
69
+ ```js
70
+ } else if (action === 'view') {
71
+ if (handlers.view) handlers.view(ta);
72
+ } else if (action === 'cta') {
73
+ if (handlers.cta) handlers.cta(ta);
74
+ } else if (action === 'help') {
75
+ if (handlers.help) handlers.help(ta);
76
+ }
77
+ ```
78
+
79
+ **Step 4: Export `onView` and `onCta` in the return object**
80
+
81
+ Find (line ~805-808):
82
+ ```js
83
+ onCollection(cb) {
84
+ handlers.collection = cb;
85
+ }
86
+ ```
87
+
88
+ Replace with:
89
+ ```js
90
+ onCollection(cb) {
91
+ handlers.collection = cb;
92
+ },
93
+ onView(cb) {
94
+ handlers.view = cb;
95
+ },
96
+ onCta(cb) {
97
+ handlers.cta = cb;
98
+ }
99
+ ```
100
+
101
+ **Step 5: Verify no syntax errors**
102
+
103
+ ```bash
104
+ cd /home/darryl/src/js/domma-cms && node --check admin/js/lib/markdown-toolbar.js
105
+ ```
106
+ Expected: exits 0, no output.
107
+
108
+ **Step 6: Commit**
109
+
110
+ ```bash
111
+ git add admin/js/lib/markdown-toolbar.js
112
+ git commit -m "feat: add view and cta action hooks to editor toolbar"
113
+ ```
114
+
115
+ ---
116
+
117
+ ## Task 2: Wire onView handler in page-editor.js
118
+
119
+ **Files:**
120
+ - Modify: `admin/js/views/page-editor.js`
121
+
122
+ **Step 1: Add the `toolbar.onView` handler after the `onCollection` block**
123
+
124
+ Find (line ~911-913):
125
+ ```js
126
+ });
127
+
128
+ // Help callback: open editor reference slideover
129
+ toolbar.onHelp(() => {
130
+ ```
131
+
132
+ Insert between them:
133
+ ```js
134
+ });
135
+
136
+ // View picker callback
137
+ toolbar.onView(async (ta) => {
138
+ const views = await api.views.list().catch(() => []);
139
+
140
+ const wrapper = document.createElement('div');
141
+ wrapper.style.cssText = 'padding:1rem;display:flex;flex-direction:column;gap:.75rem;';
142
+
143
+ const labelStyle = 'display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;';
144
+ const inputStyle = 'width:100%;padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;';
145
+
146
+ // View select
147
+ const viewRow = document.createElement('div');
148
+ const viewLabel = document.createElement('label');
149
+ viewLabel.style.cssText = labelStyle;
150
+ viewLabel.textContent = 'View';
151
+ const viewSelect = document.createElement('select');
152
+ viewSelect.style.cssText = inputStyle;
153
+ if (!views.length) {
154
+ const opt = document.createElement('option');
155
+ opt.value = '';
156
+ opt.textContent = 'No Views configured yet - create one under Data → Views';
157
+ viewSelect.appendChild(opt);
158
+ } else {
159
+ views.forEach(v => {
160
+ const opt = document.createElement('option');
161
+ opt.value = v.slug;
162
+ opt.textContent = v.title || v.slug;
163
+ viewSelect.appendChild(opt);
164
+ });
165
+ }
166
+ viewRow.appendChild(viewLabel);
167
+ viewRow.appendChild(viewSelect);
168
+ wrapper.appendChild(viewRow);
169
+
170
+ // Display mode select
171
+ const dispRow = document.createElement('div');
172
+ const dispLabel = document.createElement('label');
173
+ dispLabel.style.cssText = labelStyle;
174
+ dispLabel.textContent = 'Display';
175
+ const dispSelect = document.createElement('select');
176
+ dispSelect.style.cssText = inputStyle;
177
+ ['table', 'cards', 'list'].forEach(d => {
178
+ const opt = document.createElement('option');
179
+ opt.value = d;
180
+ opt.textContent = d.charAt(0).toUpperCase() + d.slice(1);
181
+ dispSelect.appendChild(opt);
182
+ });
183
+ dispRow.appendChild(dispLabel);
184
+ dispRow.appendChild(dispSelect);
185
+ wrapper.appendChild(dispRow);
186
+
187
+ // Insert button
188
+ const insertBtn = document.createElement('button');
189
+ insertBtn.type = 'button';
190
+ insertBtn.className = 'btn btn-primary';
191
+ insertBtn.textContent = 'Insert';
192
+ wrapper.appendChild(insertBtn);
193
+
194
+ const modal = E.modal({title: 'Insert View', size: 'sm'});
195
+ modal.element.appendChild(wrapper);
196
+ modal.open();
197
+
198
+ insertBtn.addEventListener('click', () => {
199
+ const slug = viewSelect.value;
200
+ if (!slug) return;
201
+ const snippet = `[view slug="${slug}" display="${dispSelect.value}" /]`;
202
+ modal.close();
203
+ insertAtCursor(ta, snippet);
204
+ ta.dispatchEvent(new Event('input', {bubbles: true}));
205
+ ta.focus();
206
+ });
207
+ });
208
+
209
+ // Help callback: open editor reference slideover
210
+ toolbar.onHelp(() => {
211
+ ```
212
+
213
+ **Step 2: Verify no syntax errors**
214
+
215
+ ```bash
216
+ node --check admin/js/views/page-editor.js
217
+ ```
218
+ Expected: exits 0.
219
+
220
+ **Step 3: Commit**
221
+
222
+ ```bash
223
+ git add admin/js/views/page-editor.js
224
+ git commit -m "feat: add View shortcode insert picker to page editor toolbar"
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Task 3: Wire onCta handler in page-editor.js
230
+
231
+ **Files:**
232
+ - Modify: `admin/js/views/page-editor.js`
233
+
234
+ **Step 1: Add the `toolbar.onCta` handler after the `onView` block**
235
+
236
+ Find (immediately after the view handler's closing `});` and before the help comment):
237
+ ```js
238
+ // Help callback: open editor reference slideover
239
+ toolbar.onHelp(() => {
240
+ ```
241
+
242
+ Insert between them:
243
+ ```js
244
+ // CTA picker callback
245
+ toolbar.onCta(async (ta) => {
246
+ const actions = await api.actions.list().catch(() => []);
247
+
248
+ const wrapper = document.createElement('div');
249
+ wrapper.style.cssText = 'padding:1rem;display:flex;flex-direction:column;gap:.75rem;';
250
+
251
+ const labelStyle = 'display:block;font-size:.85em;font-weight:600;margin-bottom:.25rem;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;';
252
+ const inputStyle = 'width:100%;padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;';
253
+
254
+ function makeRow(labelText, control) {
255
+ const row = document.createElement('div');
256
+ const lbl = document.createElement('label');
257
+ lbl.style.cssText = labelStyle;
258
+ lbl.textContent = labelText;
259
+ row.appendChild(lbl);
260
+ row.appendChild(control);
261
+ return row;
262
+ }
263
+
264
+ function makeSelect(options) {
265
+ const sel = document.createElement('select');
266
+ sel.style.cssText = inputStyle;
267
+ options.forEach(([val, text]) => {
268
+ const opt = document.createElement('option');
269
+ opt.value = val;
270
+ opt.textContent = text;
271
+ sel.appendChild(opt);
272
+ });
273
+ return sel;
274
+ }
275
+
276
+ function makeInput(type, placeholder, value) {
277
+ const inp = document.createElement('input');
278
+ inp.type = type;
279
+ inp.placeholder = placeholder || '';
280
+ inp.value = value || '';
281
+ inp.style.cssText = inputStyle;
282
+ return inp;
283
+ }
284
+
285
+ // Action select
286
+ const actionSelect = makeSelect(
287
+ actions.length
288
+ ? actions.map(a => [a.slug, a.title || a.slug])
289
+ : [['', 'No Actions configured yet - create one under Data → Actions']]
290
+ );
291
+ wrapper.appendChild(makeRow('Action', actionSelect));
292
+
293
+ // Label input - pre-fill from selected action's trigger label when available
294
+ const labelInput = makeInput('text', 'Button label', 'Run');
295
+ wrapper.appendChild(makeRow('Label', labelInput));
296
+
297
+ // Auto-fill label when action selection changes
298
+ actionSelect.addEventListener('change', () => {
299
+ const selected = actions.find(a => a.slug === actionSelect.value);
300
+ if (selected?.trigger?.label) labelInput.value = selected.trigger.label;
301
+ });
302
+ // Trigger once on load
303
+ if (actions.length) {
304
+ const first = actions[0];
305
+ if (first?.trigger?.label) labelInput.value = first.trigger.label;
306
+ }
307
+
308
+ // Entry ID input
309
+ const entryInput = makeInput('text', 'Paste entry UUID…', '');
310
+ wrapper.appendChild(makeRow('Entry ID', entryInput));
311
+
312
+ // Style select
313
+ const styleSelect = makeSelect([
314
+ ['primary', 'Primary'],
315
+ ['secondary', 'Secondary'],
316
+ ['ghost', 'Ghost'],
317
+ ['danger', 'Danger'],
318
+ ]);
319
+ wrapper.appendChild(makeRow('Style', styleSelect));
320
+
321
+ // Icon input
322
+ const iconInput = makeInput('text', 'e.g. check, zap, send (optional)', '');
323
+ wrapper.appendChild(makeRow('Icon', iconInput));
324
+
325
+ // Confirm input
326
+ const confirmInput = makeInput('text', 'Confirmation message (optional)', '');
327
+ wrapper.appendChild(makeRow('Confirm prompt', confirmInput));
328
+
329
+ // Insert button
330
+ const insertBtn = document.createElement('button');
331
+ insertBtn.type = 'button';
332
+ insertBtn.className = 'btn btn-primary';
333
+ insertBtn.textContent = 'Insert';
334
+ wrapper.appendChild(insertBtn);
335
+
336
+ const modal = E.modal({title: 'Insert CTA Button', size: 'sm'});
337
+ modal.element.appendChild(wrapper);
338
+ modal.open();
339
+
340
+ insertBtn.addEventListener('click', () => {
341
+ const action = actionSelect.value;
342
+ if (!action) return;
343
+ const entry = entryInput.value.trim();
344
+ const label = labelInput.value.trim() || 'Run';
345
+ const style = styleSelect.value;
346
+ const icon = iconInput.value.trim();
347
+ const confirm = confirmInput.value.trim();
348
+
349
+ let attrs = `action="${action}" entry="${entry}" style="${style}"`;
350
+ if (icon) attrs += ` icon="${icon}"`;
351
+ if (confirm) attrs += ` confirm="${confirm}"`;
352
+
353
+ const snippet = `[cta ${attrs}]${label}[/cta]`;
354
+ modal.close();
355
+ insertAtCursor(ta, snippet);
356
+ ta.dispatchEvent(new Event('input', {bubbles: true}));
357
+ ta.focus();
358
+ });
359
+ });
360
+
361
+ // Help callback: open editor reference slideover
362
+ toolbar.onHelp(() => {
363
+ ```
364
+
365
+ **Step 2: Verify no syntax errors**
366
+
367
+ ```bash
368
+ node --check admin/js/views/page-editor.js
369
+ ```
370
+ Expected: exits 0.
371
+
372
+ **Step 3: Commit**
373
+
374
+ ```bash
375
+ git add admin/js/views/page-editor.js
376
+ git commit -m "feat: add CTA shortcode insert picker to page editor toolbar"
377
+ ```
378
+
379
+ ---
380
+
381
+ ## Verification checklist
382
+
383
+ 1. Open the page editor (`#/pages` → edit any page)
384
+ 2. Click the **Insert** toolbar button (plus-circle icon) - dropdown shows: Card, Grid, Badge, Timeline, Spacer, Icon, Collection, **View**, **CTA Button**
385
+ 3. Click **View** → modal opens → if Views exist, select shows their titles; pick one, pick display mode, click Insert → `[view slug="..." display="..." /]` inserted at cursor
386
+ 4. Click **CTA Button** → modal opens → if Actions exist, select shows them; label auto-fills from action trigger; enter an entry UUID; pick style/icon/confirm; click Insert → `[cta action="..." entry="..." style="..." ...]Label[/cta]` inserted
387
+ 5. Both modals close cleanly after Insert; textarea retains focus
388
+ 6. With no Views/Actions configured: select shows the "No X configured" message; Insert button produces `[view slug="" ...]` - acceptable, no crash
@@ -0,0 +1,80 @@
1
+ # Pro Documentation - Design
2
+
3
+ **Date:** 2026-03-09
4
+ **Status:** Approved
5
+
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Add a Pro documentation section in two places:
11
+
12
+ 1. **Public Resources** - New `/resources/pro/` sub-section with individual pages for Views, Actions, and the CTA shortcode
13
+ 2. **Admin sidebar** - New "Pro Documentation" page at `#/pro/docs` with three tabs (Views, Actions, CTA Shortcode)
14
+
15
+ ---
16
+
17
+ ## Public Resources Pro Section
18
+
19
+ ### Structure
20
+
21
+ | File | URL | Description |
22
+ |------|-----|-------------|
23
+ | `content/pages/resources/pro/index.md` | `/resources/pro` | Landing page with hero + 3 cards |
24
+ | `content/pages/resources/pro/views.md` | `/resources/pro/views` | Views reference - aggregation pipelines |
25
+ | `content/pages/resources/pro/actions.md` | `/resources/pro/actions` | Actions reference - step types, templates |
26
+ | `content/pages/resources/pro/cta.md` | `/resources/pro/cta` | CTA shortcode - syntax, attributes, collection integration |
27
+
28
+ ### Page Pattern
29
+
30
+ Each page follows the existing resources convention:
31
+ - `[hero variant="dark" size="sm" fullwidth="true" twinkle twinkle-count="20" blobs]` at the top
32
+ - A `[badge]Pro[/badge]` + "Requires MongoDB" notice near the top (Views and Actions pages)
33
+ - Content with attribute tables and fenced code block examples
34
+ - `← Back to Pro Features` link at the bottom
35
+
36
+ ### Resources Index Update
37
+
38
+ Add a "Pro Features" card to `content/pages/resources/index.md` (the existing 3-column grid), linking to `/resources/pro`.
39
+
40
+ ---
41
+
42
+ ## Admin Pro Docs Panel
43
+
44
+ ### Route
45
+
46
+ `#/pro/docs`
47
+
48
+ ### Files
49
+
50
+ | File | Purpose |
51
+ |------|---------|
52
+ | `admin/js/views/pro-docs.js` | View module - `{ templateUrl, onMount }` |
53
+ | `admin/js/templates/pro-docs.html` | HTML template with three-tab layout |
54
+
55
+ ### Sidebar Entry
56
+
57
+ - Added to the admin sidebar config (in `admin/js/app.js` or wherever `getSidebarConfig` is defined)
58
+ - Section label: **"Pro"**
59
+ - Item label: **"Documentation"**
60
+ - Icon: `zap`
61
+ - Route: `#/pro/docs`
62
+ - Permission gate: visible if user has `views` OR `actions` permission
63
+
64
+ ### Tab Content
65
+
66
+ | Tab | Content |
67
+ |-----|---------|
68
+ | **Views** | What Views are; the execute pipeline; allowed `$match`/`$sort`/`$lookup` etc. stages; forbidden stages; template variable reference; worked example pipeline |
69
+ | **Actions** | What Actions are; Phase 1 step types (`updateField`, `deleteEntry`, `moveToCollection`, `webhook`, `email`); template interpolation (`{{entry.data.x}}`, `{{now}}`, `{{user.name}}`); partial execution behaviour |
70
+ | **CTA Shortcode** | Syntax (wrapping + self-closing forms); attribute table; standalone page example; collection integration example (`cta="slug"` on `[collection /]`) |
71
+
72
+ Content is written for **admin users configuring features**, not public readers. Focus on how to set up and use each feature in the admin UI.
73
+
74
+ ---
75
+
76
+ ## Out of Scope
77
+
78
+ - Live demo executions inside the admin docs panel
79
+ - Public site navigation changes (no new navbar items)
80
+ - Plugin or API documentation changes