domma-cms 0.44.0 → 0.45.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 (254) hide show
  1. package/CLAUDE.md +53 -53
  2. package/README.md +27 -27
  3. package/admin/css/admin.css +1 -1
  4. package/admin/dist/domma/domma-tools.css +3 -3
  5. package/admin/dist/domma/domma-tools.min.js +3 -3
  6. package/admin/index.html +2 -2
  7. package/admin/js/app.js +1 -1
  8. package/admin/js/lib/card-builder.js +2 -2
  9. package/admin/js/lib/crud-tutorial.js +1 -1
  10. package/admin/js/lib/effect-defs.js +1 -1
  11. package/admin/js/lib/effects-builder.js +1 -1
  12. package/admin/js/lib/image-editor.js +1 -1
  13. package/admin/js/lib/markdown-toolbar.js +2 -2
  14. package/admin/js/lib/project-context.js +1 -1
  15. package/admin/js/lib/project-quick-create.js +1 -1
  16. package/admin/js/lib/scribe-composer.js +1 -1
  17. package/admin/js/lib/server-restart.js +1 -1
  18. package/admin/js/lib/shortcode-context-menu.js +2 -2
  19. package/admin/js/lib/simple-editor.js +1 -1
  20. package/admin/js/lib/themes.js +1 -1
  21. package/admin/js/lib/timeline-builder.js +1 -1
  22. package/admin/js/templates/action-editor.html +8 -8
  23. package/admin/js/templates/api-endpoint-editor.html +7 -7
  24. package/admin/js/templates/api-endpoints.html +1 -1
  25. package/admin/js/templates/api-reference.html +1 -1
  26. package/admin/js/templates/block-editor.html +6 -6
  27. package/admin/js/templates/collection-editor.html +1 -1
  28. package/admin/js/templates/component-editor.html +2 -2
  29. package/admin/js/templates/dashboard/cache.html +3 -3
  30. package/admin/js/templates/dashboard/journeys.html +3 -3
  31. package/admin/js/templates/dashboard/kpi-strip.html +3 -3
  32. package/admin/js/templates/dashboard/top-pages.html +1 -1
  33. package/admin/js/templates/dashboard/traffic-chart.html +1 -1
  34. package/admin/js/templates/docs/api-actions.html +1 -1
  35. package/admin/js/templates/docs/api-collections.html +4 -4
  36. package/admin/js/templates/docs/api-pages.html +2 -2
  37. package/admin/js/templates/docs/api-plugins.html +1 -1
  38. package/admin/js/templates/docs/api-settings.html +2 -2
  39. package/admin/js/templates/docs/api-users.html +1 -1
  40. package/admin/js/templates/docs/components-howto.html +4 -4
  41. package/admin/js/templates/docs/components-reference.html +21 -21
  42. package/admin/js/templates/docs/components-rules.html +14 -14
  43. package/admin/js/templates/docs/components-walkthrough.html +13 -13
  44. package/admin/js/templates/docs/tutorial-crud.html +49 -49
  45. package/admin/js/templates/docs/tutorial-forms.html +4 -4
  46. package/admin/js/templates/docs/tutorial-plugin.html +10 -10
  47. package/admin/js/templates/docs/usage-actions.html +6 -6
  48. package/admin/js/templates/docs/usage-cta-shortcode.html +9 -9
  49. package/admin/js/templates/docs/usage-dconfig.html +4 -4
  50. package/admin/js/templates/docs/usage-navigation.html +1 -1
  51. package/admin/js/templates/docs/usage-pages.html +1 -1
  52. package/admin/js/templates/docs/usage-shortcodes.html +24 -24
  53. package/admin/js/templates/docs/usage-users-roles.html +3 -3
  54. package/admin/js/templates/docs/usage-views.html +4 -4
  55. package/admin/js/templates/documentation.html +1 -1
  56. package/admin/js/templates/effects.html +752 -752
  57. package/admin/js/templates/form-editor.html +5 -5
  58. package/admin/js/templates/forms.html +17 -17
  59. package/admin/js/templates/login.html +5 -5
  60. package/admin/js/templates/menu-editor.html +10 -10
  61. package/admin/js/templates/my-profile.html +17 -17
  62. package/admin/js/templates/navigation.html +11 -11
  63. package/admin/js/templates/notifications.html +1 -1
  64. package/admin/js/templates/page-editor.html +4 -4
  65. package/admin/js/templates/pro-docs.html +14 -14
  66. package/admin/js/templates/role-editor.html +70 -70
  67. package/admin/js/templates/roles.html +10 -10
  68. package/admin/js/templates/settings.html +10 -10
  69. package/admin/js/templates/tutorials.html +3 -3
  70. package/admin/js/templates/view-editor.html +15 -15
  71. package/admin/js/views/action-editor.js +1 -1
  72. package/admin/js/views/actions-list.js +1 -1
  73. package/admin/js/views/api-endpoint-editor.js +2 -2
  74. package/admin/js/views/api-endpoints.js +2 -2
  75. package/admin/js/views/api-tokens.js +3 -3
  76. package/admin/js/views/blocks.js +2 -2
  77. package/admin/js/views/collection-editor.js +1 -1
  78. package/admin/js/views/collection-entries.js +1 -1
  79. package/admin/js/views/collections.js +1 -1
  80. package/admin/js/views/component-editor.js +1 -1
  81. package/admin/js/views/components.js +4 -4
  82. package/admin/js/views/dashboard/widgets/cache.js +1 -1
  83. package/admin/js/views/dashboard/widgets/journeys.js +1 -1
  84. package/admin/js/views/dashboard/widgets/kpi-strip.js +1 -1
  85. package/admin/js/views/form-editor.js +7 -7
  86. package/admin/js/views/form-submissions.js +1 -1
  87. package/admin/js/views/forms.js +1 -1
  88. package/admin/js/views/layouts.js +1 -1
  89. package/admin/js/views/login.js +2 -2
  90. package/admin/js/views/menu-editor.js +3 -3
  91. package/admin/js/views/menu-locations.js +1 -1
  92. package/admin/js/views/menus.js +3 -3
  93. package/admin/js/views/navigation.js +8 -8
  94. package/admin/js/views/page-editor.js +40 -40
  95. package/admin/js/views/pages.js +3 -3
  96. package/admin/js/views/plugin-code.js +2 -2
  97. package/admin/js/views/plugins.js +1 -1
  98. package/admin/js/views/project-settings.js +1 -1
  99. package/admin/js/views/projects.js +1 -1
  100. package/admin/js/views/roles.js +1 -1
  101. package/admin/js/views/user-editor.js +1 -1
  102. package/admin/js/views/users.js +3 -3
  103. package/admin/js/views/view-editor.js +1 -1
  104. package/admin/js/views/view-preview.js +1 -1
  105. package/admin/js/views/views-list.js +1 -1
  106. package/bin/cli.js +8 -8
  107. package/bin/lib/config-merge.js +44 -44
  108. package/bin/update.js +16 -16
  109. package/config/plugins.json +1 -1
  110. package/package.json +2 -2
  111. package/plugins/_template/admin/views/index.js +1 -1
  112. package/plugins/_template/config.js +1 -1
  113. package/plugins/_template/plugin.js +1 -1
  114. package/plugins/analytics/admin/templates/analytics.html +3 -3
  115. package/plugins/analytics/admin/views/analytics.js +1 -1
  116. package/plugins/analytics/config.js +1 -1
  117. package/plugins/analytics/plugin.js +4 -4
  118. package/plugins/analytics/plugin.json +1 -1
  119. package/plugins/analytics/public/inject-body.html +2 -2
  120. package/plugins/analytics/public/inject-head.html +1 -1
  121. package/plugins/blog/admin/templates/blog.html +4 -4
  122. package/plugins/blog/admin/views/blog.js +3 -3
  123. package/plugins/blog/admin/views/categories.js +2 -2
  124. package/plugins/blog/admin/views/comments.js +4 -4
  125. package/plugins/blog/admin/views/post-editor.js +1 -1
  126. package/plugins/blog/plugin.js +2 -2
  127. package/plugins/blog/plugin.json +4 -4
  128. package/plugins/contacts/admin/views/contacts.js +8 -8
  129. package/plugins/contacts/plugin.js +4 -4
  130. package/plugins/contacts/plugin.json +1 -1
  131. package/plugins/invoice/admin/templates/editor.html +6 -6
  132. package/plugins/invoice/admin/templates/index.html +4 -4
  133. package/plugins/invoice/admin/views/editor.js +3 -3
  134. package/plugins/invoice/admin/views/index.js +4 -4
  135. package/plugins/invoice/admin/views/issuers.js +1 -1
  136. package/plugins/invoice/admin/views/party-view.js +3 -3
  137. package/plugins/invoice/admin/views/receivers.js +1 -1
  138. package/plugins/invoice/config.js +1 -1
  139. package/plugins/invoice/plugin.js +1 -1
  140. package/plugins/invoice/plugin.json +4 -4
  141. package/plugins/notes/admin/views/notes.js +4 -4
  142. package/plugins/notes/plugin.js +1 -1
  143. package/plugins/notes/plugin.json +1 -1
  144. package/plugins/site-search/admin/templates/site-search.html +3 -3
  145. package/plugins/site-search/admin/views/site-search.js +1 -1
  146. package/plugins/site-search/config.js +1 -1
  147. package/plugins/site-search/plugin.js +4 -4
  148. package/plugins/site-search/plugin.json +1 -1
  149. package/plugins/surveys/admin/templates/results.html +1 -1
  150. package/plugins/surveys/admin/templates/survey-editor.html +4 -4
  151. package/plugins/surveys/admin/views/audience.js +6 -6
  152. package/plugins/surveys/admin/views/results.js +3 -3
  153. package/plugins/surveys/admin/views/survey-editor.js +1 -1
  154. package/plugins/surveys/admin/views/surveys.js +2 -2
  155. package/plugins/surveys/plugin.js +1 -1
  156. package/plugins/surveys/plugin.json +4 -4
  157. package/plugins/theme-switcher/admin/views/theme-switcher.js +1 -1
  158. package/plugins/theme-switcher/plugin.json +3 -3
  159. package/plugins/theme-switcher/public/inject-body.html +28 -28
  160. package/plugins/theme-switcher/public/inject-head.html +1 -1
  161. package/plugins/todo/plugin.js +1 -1
  162. package/public/css/forms.css +1 -1
  163. package/public/js/collection-browser.js +1 -1
  164. package/public/js/collection-context.js +1 -1
  165. package/public/js/form-logic-engine.js +1 -1
  166. package/public/js/forms.js +2 -1
  167. package/public/js/site.js +1 -1
  168. package/scripts/build.js +14 -14
  169. package/scripts/create-plugin.js +2 -2
  170. package/scripts/fresh.js +2 -2
  171. package/scripts/gen-instance-secret.js +1 -1
  172. package/scripts/pro.js +12 -12
  173. package/scripts/reset.js +2 -2
  174. package/scripts/setup.js +15 -15
  175. package/scripts/users.js +5 -5
  176. package/scripts/verify-assets.mjs +6 -6
  177. package/server/config.js +1 -1
  178. package/server/middleware/auth.js +253 -253
  179. package/server/middleware/managerAuth.js +3 -3
  180. package/server/routes/api/actions.js +4 -4
  181. package/server/routes/api/api-endpoints.js +7 -7
  182. package/server/routes/api/api-tokens.js +5 -5
  183. package/server/routes/api/auth.js +309 -309
  184. package/server/routes/api/blocks.js +3 -3
  185. package/server/routes/api/collections.js +18 -18
  186. package/server/routes/api/dashboard.js +5 -5
  187. package/server/routes/api/effects.js +2 -2
  188. package/server/routes/api/endpoints-public.js +5 -5
  189. package/server/routes/api/forms.js +47 -47
  190. package/server/routes/api/menu-locations.js +3 -3
  191. package/server/routes/api/menus.js +7 -7
  192. package/server/routes/api/navigation.js +42 -42
  193. package/server/routes/api/notifications.js +2 -2
  194. package/server/routes/api/pages.js +14 -2
  195. package/server/routes/api/plugin-marketplace.js +3 -3
  196. package/server/routes/api/plugins.js +6 -6
  197. package/server/routes/api/projects.js +9 -9
  198. package/server/routes/api/scaffold.js +7 -7
  199. package/server/routes/api/settings.js +6 -6
  200. package/server/routes/api/sidebar.js +1 -1
  201. package/server/routes/api/users.js +5 -5
  202. package/server/routes/api/versions.js +1 -1
  203. package/server/routes/api/views.js +1 -1
  204. package/server/routes/docs-public.js +3 -3
  205. package/server/routes/public.js +14 -14
  206. package/server/server.js +34 -16
  207. package/server/services/actions.js +19 -19
  208. package/server/services/adapters/FileAdapter.js +2 -2
  209. package/server/services/adapters/MongoAdapter.js +5 -5
  210. package/server/services/apiEndpoints.js +15 -15
  211. package/server/services/apiTokens.js +7 -7
  212. package/server/services/blocks.js +13 -13
  213. package/server/services/cache/drivers/MemoryDriver.js +3 -3
  214. package/server/services/cache/drivers/NoneDriver.js +1 -1
  215. package/server/services/cache/index.js +5 -5
  216. package/server/services/collections.js +14 -14
  217. package/server/services/components.js +9 -9
  218. package/server/services/connectionManager.js +4 -4
  219. package/server/services/content.js +25 -2
  220. package/server/services/docs.js +14 -14
  221. package/server/services/email.js +167 -167
  222. package/server/services/filterEngine.js +6 -6
  223. package/server/services/forms.js +18 -10
  224. package/server/services/health.js +1 -1
  225. package/server/services/hooks.js +7 -7
  226. package/server/services/images.js +4 -4
  227. package/server/services/managerClient.js +1 -1
  228. package/server/services/markdown.js +79 -79
  229. package/server/services/menuRender.js +5 -5
  230. package/server/services/menus-migration.js +3 -3
  231. package/server/services/menus.js +31 -31
  232. package/server/services/permissionRegistry.js +1 -1
  233. package/server/services/pluginFiles.js +5 -5
  234. package/server/services/pluginInstaller.js +17 -17
  235. package/server/services/pluginScaffold.js +1 -1
  236. package/server/services/plugins.js +17 -17
  237. package/server/services/presetCollections.js +2 -2
  238. package/server/services/projects.js +35 -26
  239. package/server/services/recipes/contact-list.json +1 -1
  240. package/server/services/recipes/onboarding.json +8 -8
  241. package/server/services/references.js +8 -8
  242. package/server/services/renderer.js +9 -9
  243. package/server/services/roles.js +9 -9
  244. package/server/services/rowAccess.js +10 -10
  245. package/server/services/scaffolder.js +30 -30
  246. package/server/services/sidebar-migration.js +10 -10
  247. package/server/services/sitemap.js +1 -1
  248. package/server/services/userProfiles.js +199 -199
  249. package/server/services/userRoles.js +7 -7
  250. package/server/services/users.js +302 -302
  251. package/server/services/versions.js +3 -3
  252. package/server/services/viewPipeline.js +6 -6
  253. package/server/services/views.js +11 -11
  254. package/server/templates/page.html +5 -5
@@ -39,14 +39,14 @@
39
39
  <div>
40
40
  <label class="form-label">Target Collection <span style="color:var(--dm-danger,#f87171);">*</span></label>
41
41
  <select id="action-collection" class="form-input">
42
- <option value="">— select collection —</option>
42
+ <option value="">- select collection -</option>
43
43
  </select>
44
44
  <small class="text-muted">The collection this action operates on.</small>
45
45
  </div>
46
46
  <div>
47
47
  <label class="form-label">Project</label>
48
48
  <select id="action-project" class="form-input">
49
- <option value="">— none —</option>
49
+ <option value="">- none -</option>
50
50
  </select>
51
51
  <small class="text-muted">Tag this action to a project for grouping.</small>
52
52
  </div>
@@ -117,10 +117,10 @@
117
117
  <div class="card">
118
118
  <div class="card-body" style="font-size:.8rem;color:var(--dm-text-muted,#888);">
119
119
  <strong>Template variables:</strong>
120
- <code>{{entry.data.fieldName}}</code> — entry field value &nbsp;|&nbsp;
121
- <code>{{now}}</code> — current ISO timestamp &nbsp;|&nbsp;
122
- <code>{{user.name}}</code> — executing user's name &nbsp;|&nbsp;
123
- <code>{{env.CMS_PUBLIC_*}}</code> — public environment variables
120
+ <code>{{entry.data.fieldName}}</code> - entry field value &nbsp;|&nbsp;
121
+ <code>{{now}}</code> - current ISO timestamp &nbsp;|&nbsp;
122
+ <code>{{user.name}}</code> - executing user's name &nbsp;|&nbsp;
123
+ <code>{{env.CMS_PUBLIC_*}}</code> - public environment variables
124
124
  </div>
125
125
  </div>
126
126
  </div>
@@ -153,8 +153,8 @@
153
153
  <div>
154
154
  <label class="form-label">Mode</label>
155
155
  <select id="action-rowlevel-mode" class="form-input">
156
- <option value="owner">Owner — entry was created by the current user</option>
157
- <option value="field">Field Match — a field on the entry matches the user</option>
156
+ <option value="owner">Owner - entry was created by the current user</option>
157
+ <option value="field">Field Match - a field on the entry matches the user</option>
158
158
  </select>
159
159
  </div>
160
160
  <div id="action-rowlevel-field-group" style="display:none;">
@@ -44,14 +44,14 @@
44
44
  <div class="form-group">
45
45
  <label class="form-label" for="ep-mode">Mode</label>
46
46
  <select class="form-input" id="ep-mode">
47
- <option value="list">List — array of entries</option>
48
- <option value="single">Single — first match or 404</option>
47
+ <option value="list">List - array of entries</option>
48
+ <option value="single">Single - first match or 404</option>
49
49
  </select>
50
50
  </div>
51
51
  </div>
52
52
  <label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;margin-top:.5rem;padding-top:.75rem;border-top:1px solid rgba(127,127,127,.18);">
53
53
  <input type="checkbox" id="ep-enabled" checked> <strong>Enabled</strong>
54
- <span class="text-muted" style="font-size:.85rem;">— disabled endpoints return 404</span>
54
+ <span class="text-muted" style="font-size:.85rem;">- disabled endpoints return 404</span>
55
55
  </label>
56
56
  </div>
57
57
  </div>
@@ -65,7 +65,7 @@
65
65
  </div>
66
66
  <div class="card-body">
67
67
  <div id="ep-filter-rows"></div>
68
- <p class="text-muted" style="font-size:.8rem;margin:.5rem 0 0;">Values may use <code>{{params.name}}</code> (from a <code>:name</code> path segment, required) or <code>{{query.name}}</code> (optional — the filter is skipped when absent).</p>
68
+ <p class="text-muted" style="font-size:.8rem;margin:.5rem 0 0;">Values may use <code>{{params.name}}</code> (from a <code>:name</code> path segment, required) or <code>{{query.name}}</code> (optional - the filter is skipped when absent).</p>
69
69
  <div style="display:grid;grid-template-columns:2fr 1fr 1fr;gap:.75rem;margin-top:1rem;">
70
70
  <div class="form-group">
71
71
  <label class="form-label" for="ep-sort">Sort field</label>
@@ -92,7 +92,7 @@
92
92
  <div class="card">
93
93
  <div class="card-header"><h2>Response fields</h2></div>
94
94
  <div class="card-body">
95
- <p class="text-muted" style="font-size:.85rem;margin:0 0 .5rem;">Tick fields to return only those — none ticked returns everything.</p>
95
+ <p class="text-muted" style="font-size:.85rem;margin:0 0 .5rem;">Tick fields to return only those - none ticked returns everything.</p>
96
96
  <div id="ep-fields-list" style="display:flex;flex-wrap:wrap;gap:.5rem 1.25rem;"></div>
97
97
  </div>
98
98
  </div>
@@ -119,7 +119,7 @@
119
119
  <div class="form-group">
120
120
  <label class="form-label" for="tryit-query">Extra query string (optional)</label>
121
121
  <input type="text" class="form-input" id="tryit-query" placeholder="nation=France&status=published">
122
- <p class="text-muted" style="font-size:.8rem;margin:.25rem 0 0;">Applied as extra filters <em>on top of</em> the definition's own filters (which always win). Only fields this endpoint returns can be filtered; operators work too — e.g. <code>title_contains=cup</code>. <code>page</code>, <code>limit</code>, <code>sort</code> and <code>order</code> control pagination/sort instead (<code>limit</code> is capped at the endpoint's own limit); <code>search</code> is reserved.</p>
122
+ <p class="text-muted" style="font-size:.8rem;margin:.25rem 0 0;">Applied as extra filters <em>on top of</em> the definition's own filters (which always win). Only fields this endpoint returns can be filtered; operators work too - e.g. <code>title_contains=cup</code>. <code>page</code>, <code>limit</code>, <code>sort</code> and <code>order</code> control pagination/sort instead (<code>limit</code> is capped at the endpoint's own limit); <code>search</code> is reserved.</p>
123
123
  </div>
124
124
  <button class="btn btn-primary" id="tryit-send" style="width:100%;"><span data-icon="play"></span> Send</button>
125
125
  <div id="tryit-result" style="display:none;margin-top:.75rem;">
@@ -131,7 +131,7 @@
131
131
 
132
132
  <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:.4rem;">
133
133
  <span class="form-label" style="margin:0;">Response</span>
134
- <span id="tryit-status" class="badge badge-secondary">—</span>
134
+ <span id="tryit-status" class="badge badge-secondary">-</span>
135
135
  </div>
136
136
  <div id="tryit-headers-group">
137
137
  <p class="text-muted" style="font-size:.78rem;margin:0 0 .2rem;text-transform:uppercase;letter-spacing:.03em;">Headers</p>
@@ -4,7 +4,7 @@
4
4
  <a class="btn btn-primary" href="#/api-endpoints/new"><span data-icon="plus"></span> New endpoint</a>
5
5
  </div>
6
6
  </div>
7
- <p class="text-muted mb-4">Custom REST endpoints over collection data, served at <code>/api/x/&lt;project&gt;&lt;path&gt;</code>. Each endpoint binds a clean URL to a fixed collection query — definitions are data, never code.</p>
7
+ <p class="text-muted mb-4">Custom REST endpoints over collection data, served at <code>/api/x/&lt;project&gt;&lt;path&gt;</code>. Each endpoint binds a clean URL to a fixed collection query - definitions are data, never code.</p>
8
8
 
9
9
  <div class="card">
10
10
  <div class="card-body">
@@ -18,7 +18,7 @@
18
18
  </div>
19
19
 
20
20
  <p class="lead">
21
- Pick an area below — each opens as its own page, and every area is listed under
21
+ Pick an area below - each opens as its own page, and every area is listed under
22
22
  <strong>Documentation → API Reference</strong> in the sidebar.
23
23
  </p>
24
24
 
@@ -28,7 +28,7 @@
28
28
  <div class="mt-3">
29
29
  <label class="form-label">Project</label>
30
30
  <select id="block-project" class="form-input">
31
- <option value="">— none —</option>
31
+ <option value="">- none -</option>
32
32
  </select>
33
33
  <small class="text-muted">Tag this block to a project for grouping.</small>
34
34
  </div>
@@ -91,7 +91,7 @@
91
91
  </div>
92
92
  </div>
93
93
 
94
- <!-- Editor body — split pane -->
94
+ <!-- Editor body - split pane -->
95
95
  <div id="block-editor-body" class="editor-body editor-mode-split" style="min-height:460px;">
96
96
 
97
97
  <!-- Write pane -->
@@ -106,7 +106,7 @@
106
106
 
107
107
  <!-- Preview pane -->
108
108
  <div class="editor-pane editor-pane--preview" style="flex-direction:column;overflow:hidden;">
109
- <!-- Sample data inputs — auto-populated by JS -->
109
+ <!-- Sample data inputs - auto-populated by JS -->
110
110
  <div id="block-sample-data" style="
111
111
  border-bottom:1px solid var(--dm-border,rgba(255,255,255,.08));
112
112
  padding:.6rem .75rem;
@@ -139,7 +139,7 @@
139
139
  <code class="dm-code-inline" style="font-size:.9em;">@keyframes</code>,
140
140
  <code class="dm-code-inline" style="font-size:.9em;">@font-face</code>, and
141
141
  <code class="dm-code-inline" style="font-size:.9em;">@import</code>
142
- cannot be scoped — use site-wide Custom CSS in Settings for those.
142
+ cannot be scoped - use site-wide Custom CSS in Settings for those.
143
143
  </p>
144
144
  <textarea id="block-css"
145
145
  class="editor-textarea"
@@ -171,7 +171,7 @@ h2 { font-size: 1.5rem; }
171
171
  <tbody>
172
172
  <tr>
173
173
  <td><code class="dm-code-inline">&#123;&#123;fieldName&#125;&#125;</code></td>
174
- <td>Any entry field — e.g. <code class="dm-code-inline">&#123;&#123;title&#125;&#125;</code>, <code class="dm-code-inline">&#123;&#123;rating&#125;&#125;</code>,
174
+ <td>Any entry field - e.g. <code class="dm-code-inline">&#123;&#123;title&#125;&#125;</code>, <code class="dm-code-inline">&#123;&#123;rating&#125;&#125;</code>,
175
175
  <code class="dm-code-inline">&#123;&#123;message&#125;&#125;</code></td>
176
176
  </tr>
177
177
  <tr>
@@ -209,7 +209,7 @@ h2 { font-size: 1.5rem; }
209
209
  <code class="dm-code-inline">mm</code> <code class="dm-code-inline">m</code>
210
210
  <code class="dm-code-inline">ss</code> <code class="dm-code-inline">s</code>
211
211
  <code class="dm-code-inline">A</code> <code class="dm-code-inline">a</code>
212
- — any literal character that isn't one of these tokens passes through unchanged
212
+ - any literal character that isn't one of these tokens passes through unchanged
213
213
  (so <code class="dm-code-inline">DD/MM/YYYY</code>, <code class="dm-code-inline">HH:mm</code>,
214
214
  and <code class="dm-code-inline">dddd D MMMM YYYY</code> all work).
215
215
  </p>
@@ -57,7 +57,7 @@
57
57
  <div class="col-6">
58
58
  <label class="form-label">Project</label>
59
59
  <select id="collection-project" class="form-input">
60
- <option value="">— none —</option>
60
+ <option value="">- none -</option>
61
61
  </select>
62
62
  <p class="form-hint text-muted" style="margin-top:.3rem;font-size:.8rem;">Tag this collection to a project for grouping.</p>
63
63
  </div>
@@ -31,7 +31,7 @@
31
31
  <div class="mt-3">
32
32
  <label class="form-label">Project</label>
33
33
  <select id="component-project" class="form-input">
34
- <option value="">— none —</option>
34
+ <option value="">- none -</option>
35
35
  </select>
36
36
  <small class="text-muted">Tag this component to a project for grouping.</small>
37
37
  </div>
@@ -43,7 +43,7 @@
43
43
  </div>
44
44
  </div>
45
45
 
46
- <!-- Editor body — tabs on the left, preview on the right -->
46
+ <!-- Editor body - tabs on the left, preview on the right -->
47
47
  <div class="card card-collapsible editor-card mb-3">
48
48
  <div class="card-header">
49
49
  <h2>Source</h2>
@@ -8,12 +8,12 @@
8
8
  <div class="dash-cache-grid">
9
9
  <div class="dash-cache-stat">
10
10
  <div class="dash-cache-stat-label">Hit rate</div>
11
- <div class="dash-cache-stat-value" data-field="hit-rate">—</div>
11
+ <div class="dash-cache-stat-value" data-field="hit-rate">-</div>
12
12
  <div class="dash-cache-stat-sub" data-field="hits-misses">no traffic yet</div>
13
13
  </div>
14
14
  <div class="dash-cache-stat">
15
15
  <div class="dash-cache-stat-label">Entries</div>
16
- <div class="dash-cache-stat-value" data-field="size">—</div>
16
+ <div class="dash-cache-stat-value" data-field="size">-</div>
17
17
  <div class="dash-cache-stat-sub" data-field="size-bar"><span data-field="size-fill"></span></div>
18
18
  </div>
19
19
  <div class="dash-cache-stat">
@@ -24,7 +24,7 @@
24
24
  <div class="dash-cache-stat">
25
25
  <div class="dash-cache-stat-label">Last cleared</div>
26
26
  <div class="dash-cache-stat-value" data-field="last-cleared">never</div>
27
- <div class="dash-cache-stat-sub" data-field="driver">driver: —</div>
27
+ <div class="dash-cache-stat-sub" data-field="driver">driver: -</div>
28
28
  </div>
29
29
  </div>
30
30
  <div class="dash-cache-actions">
@@ -1,4 +1,4 @@
1
- <h3>User journeys — last 7 days</h3>
1
+ <h3>User journeys - last 7 days</h3>
2
2
  <div class="dash-journey-grid">
3
3
  <div>
4
4
  <h4>Top entry pages</h4>
@@ -13,5 +13,5 @@
13
13
  <div data-field="paths"></div>
14
14
  </div>
15
15
  </div>
16
- <p class="dash-bounce">Bounce rate: <strong data-field="bounce">—</strong></p>
17
- <p class="dash-empty" hidden>No journey data yet — encourage some traffic and check back.</p>
16
+ <p class="dash-bounce">Bounce rate: <strong data-field="bounce">-</strong></p>
17
+ <p class="dash-empty" hidden>No journey data yet - encourage some traffic and check back.</p>
@@ -1,7 +1,7 @@
1
1
  <div class="dash-card dash-kpi">
2
2
  <span class="dash-kpi-icon" data-icon="trending-up"></span>
3
3
  <div>
4
- <div class="dash-kpi-value" data-field="hits-today">—</div>
4
+ <div class="dash-kpi-value" data-field="hits-today">-</div>
5
5
  <div class="dash-kpi-label">Hits today</div>
6
6
  <div class="dash-kpi-delta" data-field="hits-delta"></div>
7
7
  </div>
@@ -9,14 +9,14 @@
9
9
  <div class="dash-card dash-kpi">
10
10
  <span class="dash-kpi-icon" data-icon="users"></span>
11
11
  <div>
12
- <div class="dash-kpi-value" data-field="active-sessions">—</div>
12
+ <div class="dash-kpi-value" data-field="active-sessions">-</div>
13
13
  <div class="dash-kpi-label">Active sessions (5m)</div>
14
14
  </div>
15
15
  </div>
16
16
  <div class="dash-card dash-kpi">
17
17
  <span class="dash-kpi-icon" data-icon="inbox"></span>
18
18
  <div>
19
- <div class="dash-kpi-value" data-field="submissions-week">—</div>
19
+ <div class="dash-kpi-value" data-field="submissions-week">-</div>
20
20
  <div class="dash-kpi-label">Submissions this week</div>
21
21
  </div>
22
22
  </div>
@@ -1,3 +1,3 @@
1
- <h3>Top pages — last 7 days</h3>
1
+ <h3>Top pages - last 7 days</h3>
2
2
  <div data-field="rows"></div>
3
3
  <p class="dash-empty" hidden>No traffic recorded yet.</p>
@@ -1,3 +1,3 @@
1
- <h3>Traffic — last 30 days</h3>
1
+ <h3>Traffic - last 30 days</h3>
2
2
  <div class="dash-chart-wrap"><canvas id="dash-traffic-canvas"></canvas></div>
3
3
  <p class="dash-empty" hidden>No traffic recorded yet.</p>
@@ -138,7 +138,7 @@
138
138
  <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/actions/:slug/public</span>
139
139
  </h3>
140
140
  <p class="auth-note">Requires: JWT + role in <code>access.roles</code></p>
141
- <p>Execute an action publicly. Always requires a valid JWT — the role is checked against <code>access.roles</code>.
141
+ <p>Execute an action publicly. Always requires a valid JWT - the role is checked against <code>access.roles</code>.
142
142
  Request body and response shape are identical to the admin <code>/execute</code> endpoint.</p>
143
143
 
144
144
  </div>
@@ -156,7 +156,7 @@
156
156
  </tr>
157
157
  </tbody>
158
158
  </table>
159
- <pre class="code-block"><code>// Response 201 — returns the created schema object
159
+ <pre class="code-block"><code>// Response 201 - returns the created schema object
160
160
 
161
161
  // Error 409
162
162
  { "error": "A collection with that slug already exists" }</code></pre>
@@ -219,7 +219,7 @@
219
219
  </tr>
220
220
  <tr>
221
221
  <td><code>search</code></td>
222
- <td>—</td>
222
+ <td>-</td>
223
223
  <td>Full-text search query</td>
224
224
  </tr>
225
225
  </tbody>
@@ -236,7 +236,7 @@
236
236
  </h3>
237
237
  <p class="auth-note">Requires Bearer token + <code>collections</code> permission.</p>
238
238
  <p>Create a new entry. Data is validated against the collection schema.</p>
239
- <pre class="code-block"><code>// Response 201 — returns the created entry</code></pre>
239
+ <pre class="code-block"><code>// Response 201 - returns the created entry</code></pre>
240
240
 
241
241
  <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/collections/:slug/entries/:id</span>
242
242
  </h3>
@@ -280,7 +280,7 @@
280
280
  </tr>
281
281
  </tbody>
282
282
  </table>
283
- <pre class="code-block"><code>// Response 200 — file download
283
+ <pre class="code-block"><code>// Response 200 - file download
284
284
  // Content-Disposition: attachment; filename="blog-entries.json"</code></pre>
285
285
 
286
286
  <h3><span class="method-badge method-post">POST</span><span class="endpoint-path">/api/collections/:slug/import</span>
@@ -159,7 +159,7 @@
159
159
  </tr>
160
160
  </tbody>
161
161
  </table>
162
- <pre class="code-block"><code>// Response 201 — returns the created page object</code></pre>
162
+ <pre class="code-block"><code>// Response 201 - returns the created page object</code></pre>
163
163
 
164
164
  <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/pages/*</span>
165
165
  </h3>
@@ -191,7 +191,7 @@
191
191
  </tr>
192
192
  </tbody>
193
193
  </table>
194
- <pre class="code-block"><code>// Response 200 — returns the updated page object
194
+ <pre class="code-block"><code>// Response 200 - returns the updated page object
195
195
 
196
196
  // Error 404
197
197
  { "error": "Page not found" }
@@ -122,7 +122,7 @@
122
122
  <h3><span class="method-badge method-get">GET</span><span class="endpoint-path">/api/plugins/admin-config</span>
123
123
  </h3>
124
124
  <p class="auth-note">Requires Bearer token (any role).</p>
125
- <p>Return the merged admin configuration for all enabled plugins — sidebar items, SPA routes, and view
125
+ <p>Return the merged admin configuration for all enabled plugins - sidebar items, SPA routes, and view
126
126
  entry points.</p>
127
127
  <pre class="code-block"><code>// Response 200
128
128
  {
@@ -79,9 +79,9 @@
79
79
  <h3><span class="method-badge method-put">PUT</span><span class="endpoint-path">/api/settings</span>
80
80
  </h3>
81
81
  <p class="auth-note">Requires Bearer token + <code>settings</code> permission.</p>
82
- <p>Replace the site settings object. Send the full merged object — partial updates overwrite the
82
+ <p>Replace the site settings object. Send the full merged object - partial updates overwrite the
83
83
  entire config.</p>
84
- <pre class="code-block"><code>// Request body — full site settings object
84
+ <pre class="code-block"><code>// Request body - full site settings object
85
85
  { "siteName": "My Site", "adminTheme": "ocean-dark", ... }
86
86
 
87
87
  // Response 200
@@ -172,7 +172,7 @@
172
172
  </tr>
173
173
  </tbody>
174
174
  </table>
175
- <pre class="code-block"><code>// Response 200 — returns the updated user object</code></pre>
175
+ <pre class="code-block"><code>// Response 200 - returns the updated user object</code></pre>
176
176
 
177
177
  <h3><span class="method-badge method-delete">DELETE</span><span
178
178
  class="endpoint-path">/api/users/:id</span></h3>
@@ -1,5 +1,5 @@
1
1
  <div class="view-header">
2
- <h1><span data-icon="component"></span> Components — How-To</h1>
2
+ <h1><span data-icon="component"></span> Components - How-To</h1>
3
3
  <a href="#/components/new" class="btn btn-primary btn-sm"><span data-icon="plus"></span> New Component</a>
4
4
  </div>
5
5
 
@@ -28,7 +28,7 @@
28
28
  becomes the tag <code>&lt;dm-price-tag&gt;</code>.</li>
29
29
  <li>Fill the <code>&lt;template&gt;</code>, <code>&lt;props&gt;</code> and <code>&lt;script&gt;</code>
30
30
  tabs (the editor watches the live preview as you type).</li>
31
- <li><strong>Save</strong>. It compiles first — fix any reported errors and it lands on disk.</li>
31
+ <li><strong>Save</strong>. It compiles first - fix any reported errors and it lands on disk.</li>
32
32
  </ol>
33
33
 
34
34
  <hr>
@@ -49,7 +49,7 @@
49
49
 
50
50
  <h2>Add state and respond to a click</h2>
51
51
  <p>Render the markup with <code>data-action</code> hooks, then attach <strong>one</strong> delegated
52
- listener to the shadow root in <code>onMount</code>. Mutate state with <code>this.set()</code> — the
52
+ listener to the shadow root in <code>onMount</code>. Mutate state with <code>this.set()</code> - the
53
53
  template re-renders automatically.</p>
54
54
  <pre class="code-block"><code>&lt;template&gt;
55
55
  &lt;div class="dm-counter"&gt;
@@ -153,7 +153,7 @@ onMount() { this.set({ count: this.props.initial }); }</code></pre>
153
153
  <h2>Move a component between sites</h2>
154
154
  <ol>
155
155
  <li>On <a href="#/components">Components</a>, click <span data-icon="download"></span> Export on the
156
- row — you'll download <code>name.dmcomponent.json</code>.</li>
156
+ row - you'll download <code>name.dmcomponent.json</code>.</li>
157
157
  <li>On the other site, click <strong>Import</strong> and pick that file. On a name clash you'll be
158
158
  asked to confirm an overwrite.</li>
159
159
  </ol>
@@ -1,5 +1,5 @@
1
1
  <div class="view-header">
2
- <h1><span data-icon="component"></span> Components — Reference</h1>
2
+ <h1><span data-icon="component"></span> Components - Reference</h1>
3
3
  <a href="#/components" class="btn btn-ghost btn-sm"><span data-icon="component"></span> Manage Components</a>
4
4
  </div>
5
5
 
@@ -17,8 +17,8 @@
17
17
 
18
18
  <p class="lead">
19
19
  Components are small, reusable custom elements you author in one file and drop into any page.
20
- Each one is a single <code>.dmc</code> file with up to four sections — <code>&lt;template&gt;</code>,
21
- <code>&lt;props&gt;</code>, <code>&lt;script&gt;</code> and <code>&lt;style&gt;</code> — and the CMS
20
+ Each one is a single <code>.dmc</code> file with up to four sections - <code>&lt;template&gt;</code>,
21
+ <code>&lt;props&gt;</code>, <code>&lt;script&gt;</code> and <code>&lt;style&gt;</code> - and the CMS
22
22
  compiles it to a self-contained browser module that registers a
23
23
  <code>&lt;dm-<em>name</em>&gt;</code> custom element. No build step, no framework wiring.
24
24
  </p>
@@ -55,13 +55,13 @@ export default {};
55
55
  .dm-greeting { font-weight: 600; }
56
56
  &lt;/style&gt;</code></pre>
57
57
 
58
- <p>Saving compiles the source <em>before</em> it is written to disk — a malformed component never
58
+ <p>Saving compiles the source <em>before</em> it is written to disk - a malformed component never
59
59
  reaches the filesystem. The compiler reports precise, per-block errors (see
60
60
  <a href="#/docs/components-rules">Rules</a> for every error code).</p>
61
61
 
62
62
  <hr>
63
63
 
64
- <h2><code>&lt;template&gt;</code> — markup</h2>
64
+ <h2><code>&lt;template&gt;</code> - markup</h2>
65
65
 
66
66
  <p>Plain HTML plus a Handlebars-style expression syntax. Data comes from the component's
67
67
  <code>props</code> and reactive <code>data()</code> state. Supported syntax:</p>
@@ -92,7 +92,7 @@ export default {};
92
92
 
93
93
  <hr>
94
94
 
95
- <h2><code>&lt;props&gt;</code> — typed inputs</h2>
95
+ <h2><code>&lt;props&gt;</code> - typed inputs</h2>
96
96
 
97
97
  <p>A JSON <strong>object</strong> (not an array). Each key is a prop name; each value declares a
98
98
  <code>type</code> and may add a <code>default</code> and a <code>label</code> (shown in the editor's
@@ -110,17 +110,17 @@ export default {};
110
110
 
111
111
  <p>Props are passed as HTML attributes where the value is always a string; the runtime coerces it to
112
112
  the declared type (so <code>step="2"</code> arrives as the number <code>2</code>). Read props inside
113
- <code>onMount()</code> and methods via <code>this.props</code> — see the script API below.</p>
113
+ <code>onMount()</code> and methods via <code>this.props</code> - see the script API below.</p>
114
114
 
115
115
  <hr>
116
116
 
117
- <h2><code>&lt;script&gt;</code> — behaviour</h2>
117
+ <h2><code>&lt;script&gt;</code> - behaviour</h2>
118
118
 
119
119
  <p>An ES module with a single <code>export default { … }</code> object describing the component. The
120
120
  export is the only requirement; every key inside it is optional.</p>
121
121
 
122
122
  <pre class="code-block"><code>export default {
123
- // Reactive state. Called WITHOUT `this` — do not read props here.
123
+ // Reactive state. Called WITHOUT `this` - do not read props here.
124
124
  data() { return { count: 0 }; },
125
125
 
126
126
  // Methods are bound to the component context (`this`).
@@ -128,7 +128,7 @@ export default {};
128
128
  inc() { this.set({ count: this.data.count + this.props.step }); }
129
129
  },
130
130
 
131
- // Lifecycle — bound to `this`; props and the element are available here.
131
+ // Lifecycle - bound to `this`; props and the element are available here.
132
132
  onMount() { this.set({ count: this.props.initial }); },
133
133
  onUnmount() { /* clean up timers, listeners, etc. */ }
134
134
  };</code></pre>
@@ -138,10 +138,10 @@ export default {};
138
138
  <tr><th>Key</th><th>What it is</th></tr>
139
139
  </thead>
140
140
  <tbody>
141
- <tr><td><code>data()</code></td><td>Returns the initial reactive state object. Called with no <code>this</code> binding — <strong>props are not available here</strong>; initialise from props in <code>onMount()</code>.</td></tr>
141
+ <tr><td><code>data()</code></td><td>Returns the initial reactive state object. Called with no <code>this</code> binding - <strong>props are not available here</strong>; initialise from props in <code>onMount()</code>.</td></tr>
142
142
  <tr><td><code>methods</code></td><td>Object of functions bound to the component context.</td></tr>
143
143
  <tr><td><code>onMount()</code></td><td>Lifecycle hook fired when the element is attached to the DOM. Props and the element node are available.</td></tr>
144
- <tr><td><code>onUnmount()</code></td><td>Lifecycle hook fired when the element is removed — clear intervals/listeners here.</td></tr>
144
+ <tr><td><code>onUnmount()</code></td><td>Lifecycle hook fired when the element is removed - clear intervals/listeners here.</td></tr>
145
145
  </tbody>
146
146
  </table>
147
147
 
@@ -155,7 +155,7 @@ export default {};
155
155
  <tr><td><code>this.props</code></td><td>The (type-coerced) props the element was used with.</td></tr>
156
156
  <tr><td><code>this.data</code></td><td>The current reactive state snapshot.</td></tr>
157
157
  <tr><td><code>this.set({ … })</code></td><td>Patch reactive state; the template re-renders with the new values.</td></tr>
158
- <tr><td><code>this.el</code></td><td>The custom-element DOM node. Its rendered markup lives in <code>this.el.shadowRoot</code> — attach event listeners there.</td></tr>
158
+ <tr><td><code>this.el</code></td><td>The custom-element DOM node. Its rendered markup lives in <code>this.el.shadowRoot</code> - attach event listeners there.</td></tr>
159
159
  </tbody>
160
160
  </table>
161
161
 
@@ -165,7 +165,7 @@ export default {};
165
165
 
166
166
  <hr>
167
167
 
168
- <h2><code>&lt;style&gt;</code> — scoped CSS</h2>
168
+ <h2><code>&lt;style&gt;</code> - scoped CSS</h2>
169
169
 
170
170
  <p>Optional. CSS here is scoped to the component's shadow DOM, so selectors can't leak out and the
171
171
  page's styles can't leak in. By convention components prefix their root class with
@@ -231,7 +231,7 @@ export default {};
231
231
 
232
232
  <h3>Bundled &amp; plugin components</h3>
233
233
  <p>The <code>bundled</code> flag marks a component as part of fresh-install seed data. Plugins may
234
- also contribute components via the <code>registerComponent()</code> hook — these appear in the list
234
+ also contribute components via the <code>registerComponent()</code> hook - these appear in the list
235
235
  with a <span class="badge badge-secondary">plugin</span> badge, are served from memory, and are
236
236
  <strong>read-only</strong> from the admin (you can't edit or delete them, and you can't save a
237
237
  component whose name a plugin already owns).</p>
@@ -239,14 +239,14 @@ export default {};
239
239
  <hr>
240
240
 
241
241
  <h2>The five seeded starter components</h2>
242
- <p>Fresh installs ship with these (never overwritten if you've edited them) — open any in
242
+ <p>Fresh installs ship with these (never overwritten if you've edited them) - open any in
243
243
  <a href="#/components">Components</a> to read the full source:</p>
244
244
  <ul>
245
- <li><code>counter</code> — state, methods and lifecycle in one small example</li>
246
- <li><code>copy-button</code> — an async method using the clipboard API</li>
247
- <li><code>reveal-panel</code> — conditional rendering plus a <code>&lt;slot&gt;</code></li>
248
- <li><code>testimonial-card</code> — presentational only (empty <code>export default {}</code>)</li>
249
- <li><code>countdown-timer</code> — an interval started in <code>onMount</code> and cleared in <code>onUnmount</code></li>
245
+ <li><code>counter</code> - state, methods and lifecycle in one small example</li>
246
+ <li><code>copy-button</code> - an async method using the clipboard API</li>
247
+ <li><code>reveal-panel</code> - conditional rendering plus a <code>&lt;slot&gt;</code></li>
248
+ <li><code>testimonial-card</code> - presentational only (empty <code>export default {}</code>)</li>
249
+ <li><code>countdown-timer</code> - an interval started in <code>onMount</code> and cleared in <code>onUnmount</code></li>
250
250
  </ul>
251
251
 
252
252
  <hr>