domma-cms 1.6.60 → 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 (137) 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/lib/effect-defs.js +1 -1
  6. package/admin/js/lib/effects-builder.js +2 -2
  7. package/admin/js/lib/page-editor-reference.js +5 -5
  8. package/admin/js/lib/shortcode-tags.js +1 -1
  9. package/admin/js/templates/docs/usage-shortcodes.html +39 -0
  10. package/docs/DommaFeatures.md +3005 -0
  11. package/docs/MultiTenant.md +176 -0
  12. package/docs/api-reference.md +1667 -0
  13. package/docs/cache.md +96 -0
  14. package/docs/configuration.md +1811 -0
  15. package/docs/editions-and-licences.md +190 -0
  16. package/docs/getting-started.md +201 -0
  17. package/docs/guides/form-triggers.md +260 -0
  18. package/docs/guides/mongodb-storage-adapter.md +282 -0
  19. package/docs/guides/multi-page-forms.md +121 -0
  20. package/docs/images/scribe-composer.png +0 -0
  21. package/docs/markdown-shortcodes.md +1738 -0
  22. package/docs/pentest-report-2026-04-03.md +181 -0
  23. package/docs/plans/2026-02-28-admin-topbar-login-forms.md +349 -0
  24. package/docs/plans/2026-02-28-domma-ui-polish.md +286 -0
  25. package/docs/plans/2026-02-28-reset-seed-fresh-commands.md +520 -0
  26. package/docs/plans/2026-03-02-cookie-consent-design.md +86 -0
  27. package/docs/plans/2026-03-02-cookie-consent-plugin.md +453 -0
  28. package/docs/plans/2026-03-02-tooltip-sweep-and-back-to-top-plugin-design.md +126 -0
  29. package/docs/plans/2026-03-02-tooltip-sweep-back-to-top.md +427 -0
  30. package/docs/plans/2026-03-05-cookie-consent-btt-core.md +115 -0
  31. package/docs/plans/2026-03-05-custom-css-migrate-to-core-design.md +35 -0
  32. package/docs/plans/2026-03-05-custom-css-migrate-to-core.md +352 -0
  33. package/docs/plans/2026-03-05-scribe-script-shortcode.md +373 -0
  34. package/docs/plans/2026-03-05-user-types-design.md +139 -0
  35. package/docs/plans/2026-03-05-user-types-implementation.md +1035 -0
  36. package/docs/plans/2026-03-09-page-editor-view-cta-inserts-design.md +78 -0
  37. package/docs/plans/2026-03-09-page-editor-view-cta-inserts.md +388 -0
  38. package/docs/plans/2026-03-09-pro-documentation-design.md +80 -0
  39. package/docs/plans/2026-03-09-pro-documentation.md +1017 -0
  40. package/docs/plans/2026-06-10-core-project-design.md +240 -0
  41. package/docs/plugin-development.md +827 -0
  42. package/docs/recruitment-recipe.md +501 -0
  43. package/docs/scaffolding.md +312 -0
  44. package/docs/screenshots/calculator-floating.png +0 -0
  45. package/docs/screenshots/calculator-standard.png +0 -0
  46. package/docs/screenshots/email-settings.png +0 -0
  47. package/docs/screenshots/messages-count.png +0 -0
  48. package/docs/structure/user-types.md +107 -0
  49. package/docs/superpowers/plans/2026-05-25-admin-sidebar-via-menus.md +1112 -0
  50. package/docs/superpowers/plans/2026-06-08-navbar-mobile-drawer-and-menu-enrichment.md +1161 -0
  51. package/docs/superpowers/plans/2026-06-25-domma-docs-project.md +695 -0
  52. package/docs/superpowers/plans/2026-06-26-surveys-HANDOFF.md +68 -0
  53. package/docs/superpowers/plans/2026-06-26-surveys-pro-plugin.md +1902 -0
  54. package/docs/superpowers/plans/2026-08-19-collection-context-sort-export.md +1577 -0
  55. package/docs/superpowers/plans/2026-10-09-content-api.md +1192 -0
  56. package/docs/superpowers/specs/2026-03-12-form-followup-actions-design.md +152 -0
  57. package/docs/superpowers/specs/2026-03-12-page-editor-form-insert-and-per-page-theme-design.md +115 -0
  58. package/docs/superpowers/specs/2026-03-17-nav-hidden-items-design.md +85 -0
  59. package/docs/superpowers/specs/2026-03-19-accordion-insert-design.md +175 -0
  60. package/docs/superpowers/specs/2026-03-25-static-block-shortcode-design.md +153 -0
  61. package/docs/superpowers/specs/2026-03-25-text-shortcode-design.md +168 -0
  62. package/docs/superpowers/specs/2026-04-05-card-builder-design.md +315 -0
  63. package/docs/superpowers/specs/2026-04-06-insert-builders-design.md +278 -0
  64. package/docs/superpowers/specs/2026-04-06-layouts-design.md +226 -0
  65. package/docs/superpowers/specs/2026-04-07-blog-plugin-design.md +300 -0
  66. package/docs/superpowers/specs/2026-04-07-calendar-plugin-design.md +538 -0
  67. package/docs/superpowers/specs/2026-04-17-components-area-design.md +368 -0
  68. package/docs/superpowers/specs/2026-05-02-effects-slideover-overhaul-design.md +193 -0
  69. package/docs/superpowers/specs/2026-05-06-dashboard-rebuild-design.md +257 -0
  70. package/docs/superpowers/specs/2026-05-24-menus-design.md +466 -0
  71. package/docs/superpowers/specs/2026-05-25-admin-sidebar-via-menus-design.md +358 -0
  72. package/docs/superpowers/specs/2026-05-25-projects-design.md +380 -0
  73. package/docs/superpowers/specs/2026-06-08-navbar-mobile-drawer-and-menu-enrichment-design.md +292 -0
  74. package/docs/superpowers/specs/2026-06-08-sidebar-tools-plugins-folders-design.md +59 -0
  75. package/docs/superpowers/specs/2026-06-25-domma-docs-project-design.md +192 -0
  76. package/docs/superpowers/specs/2026-06-26-domma-charts-upstream-proposal.md +44 -0
  77. package/docs/superpowers/specs/2026-06-26-manager-scheduler-upstream-proposal.md +46 -0
  78. package/docs/superpowers/specs/2026-06-26-surveys-pro-plugin-design.md +206 -0
  79. package/docs/superpowers/specs/2026-07-02-shortcode-context-menu-design.md +96 -0
  80. package/docs/superpowers/specs/2026-08-19-collection-context-sort-export-design.md +330 -0
  81. package/docs/superpowers/specs/2026-09-22-dcms-marketplace-design.md +1150 -0
  82. package/docs/superpowers/specs/2026-10-09-content-api-design.md +325 -0
  83. package/docs/superpowers/specs/plans/2026-03-12-form-followup-actions.md +624 -0
  84. package/docs/superpowers/specs/plans/2026-03-12-page-editor-form-insert-and-per-page-theme.md +125 -0
  85. package/docs/superpowers/specs/plans/2026-03-17-nav-hidden-items.md +578 -0
  86. package/docs/superpowers/specs/plans/2026-03-19-accordion-insert.md +635 -0
  87. package/docs/superpowers/specs/plans/2026-03-25-text-shortcode.md +545 -0
  88. package/docs/superpowers/specs/plans/2026-04-05-card-builder.md +1970 -0
  89. package/docs/superpowers/specs/plans/2026-04-06-insert-builders.md +1049 -0
  90. package/docs/superpowers/specs/plans/2026-04-06-layouts.md +1015 -0
  91. package/docs/superpowers/specs/plans/2026-04-07-calendar-plugin.md +1526 -0
  92. package/docs/superpowers/specs/plans/2026-04-08-plugin-monetisation-split.md +242 -0
  93. package/docs/superpowers/specs/plans/2026-04-17-components-area.md +2038 -0
  94. package/docs/superpowers/specs/plans/2026-05-02-effects-slideover-overhaul.md +2335 -0
  95. package/docs/superpowers/specs/plans/2026-05-06-dashboard-rebuild.md +1999 -0
  96. package/docs/superpowers/specs/plans/2026-05-17-cache-system.md +1436 -0
  97. package/docs/superpowers/specs/plans/2026-05-24-menus.md +3096 -0
  98. package/docs/superpowers/specs/plans/2026-05-25-projects.md +2869 -0
  99. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step2-consolidation.md +505 -0
  100. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step3-catalogue-and-key.md +154 -0
  101. package/docs/superpowers/specs/plans/2026-09-22-tools-promotion.md +260 -0
  102. package/docs/theming.md +320 -0
  103. package/package.json +2 -2
  104. package/public/js/celebrations/core/canvas.js +1 -1
  105. package/public/js/celebrations/index.js +1 -1
  106. package/public/js/celebrations/licenses/ABeeZee-Regular-OFL.txt +93 -0
  107. package/public/js/celebrations/licenses/Allura-Regular-OFL.txt +93 -0
  108. package/public/js/celebrations/message-attrs.mjs +1 -0
  109. package/public/js/celebrations/themes/anniversary.js +1 -0
  110. package/public/js/celebrations/themes/autumn.js +1 -0
  111. package/public/js/celebrations/themes/birthday.js +1 -0
  112. package/public/js/celebrations/themes/butterfly-flight.js +1 -0
  113. package/public/js/celebrations/themes/calendar.js +1 -0
  114. package/public/js/celebrations/themes/chinese-new-year-dates.js +1 -0
  115. package/public/js/celebrations/themes/chinese-new-year.js +1 -0
  116. package/public/js/celebrations/themes/christmas.js +1 -1
  117. package/public/js/celebrations/themes/easter.js +1 -0
  118. package/public/js/celebrations/themes/garden-drawing.js +1 -0
  119. package/public/js/celebrations/themes/garden.js +1 -0
  120. package/public/js/celebrations/themes/graduation.js +1 -0
  121. package/public/js/celebrations/themes/greeting.js +1 -0
  122. package/public/js/celebrations/themes/make-it-rain.js +1 -0
  123. package/public/js/celebrations/themes/money-rain.js +1 -0
  124. package/public/js/celebrations/themes/new-year.js +1 -0
  125. package/public/js/celebrations/themes/occasion-drawing.js +1 -0
  126. package/public/js/celebrations/themes/occasions.js +1 -0
  127. package/public/js/celebrations/themes/rain-control.js +1 -0
  128. package/public/js/celebrations/themes/sparkler-font-data.js +1 -0
  129. package/public/js/celebrations/themes/sparkler-font.js +1 -0
  130. package/public/js/celebrations/themes/sparkler-writing.js +1 -0
  131. package/public/js/celebrations/themes/summer-garden.js +1 -0
  132. package/public/js/celebrations/themes/winter.js +1 -0
  133. package/public/js/celebrations/trait-data.mjs +1 -1
  134. package/public/js/effects.js +1 -1
  135. package/scripts/build.js +4 -0
  136. package/server/services/markdown.js +5 -2
  137. package/server/templates/page.html +1 -1
@@ -0,0 +1,168 @@
1
+ # Design Spec: `[text]` Shortcode
2
+
3
+ **Date:** 2026-03-25
4
+ **Status:** Approved
5
+
6
+ ## Overview
7
+
8
+ Add a `[text]` shortcode that renders a `<span>` with inline styles, giving content authors a simple, readable way to
9
+ apply rich text formatting directly in Markdown without writing raw HTML.
10
+
11
+ The shortcode is accessible via the existing Page Editor Insert icon menu (the `plus-circle` dropdown), which opens a
12
+ modal letting users configure options and preview the result before inserting.
13
+
14
+ ---
15
+
16
+ ## Shortcode Syntax
17
+
18
+ ```
19
+ [text size="xl" bold italic color="primary" font="Georgia"]Your text[/text]
20
+ ```
21
+
22
+ Renders:
23
+
24
+ ```html
25
+ <span style="font-size:1.25rem;font-weight:700;font-style:italic;color:var(--dm-color-primary);font-family:Georgia,serif;">Your text</span>
26
+ ```
27
+
28
+ Only attributes that differ from defaults are emitted. All attributes are optional. Paired syntax only - no self-closing
29
+ form.
30
+
31
+ ---
32
+
33
+ ## Supported Attributes
34
+
35
+ | Attribute | Values | CSS Property |
36
+ |--------------|---------------------------------------------------------------------------------------|---------------------|
37
+ | `size` | `xs` `sm` `base` `lg` `xl` `2xl` `3xl` `4xl` or raw (e.g. `"1.5em"`) | `font-size` |
38
+ | `weight` | `thin` `light` `normal` `medium` `semibold` `bold` `extrabold` `black` | `font-weight` |
39
+ | `bold` | flag (presence in raw attr string) | `font-weight:700` |
40
+ | `italic` | flag (presence in raw attr string) | `font-style:italic` |
41
+ | `color` | CSS color OR token: `primary` `secondary` `muted` `danger` `success` `warning` `info` | `color` |
42
+ | `font` | `Georgia` `Arial` `Verdana` `Courier New` `Times New Roman` `Trebuchet MS` | `font-family` |
43
+ | `transform` | `upper` `lower` `capitalize` `none` | `text-transform` |
44
+ | `decoration` | `underline` `line-through` `none` | `text-decoration` |
45
+ | `spacing` | `tight` `normal` `wide` `wider` or raw (e.g. `"0.1em"`) | `letter-spacing` |
46
+ | `class` | Extra CSS class(es) | `class` attribute |
47
+ | `id` | Element ID | `id` attribute |
48
+
49
+ > **Note:** `align` (`text-align`) is intentionally excluded. `text-align` has no effect on inline `<span>` elements.
50
+ > Use the `[center]` shortcode for centering, or wrap content in a `[card]` / `[grid]` for other alignment needs.
51
+
52
+ ### Size token map
53
+
54
+ `xs→.75rem` · `sm→.875rem` · `base→1rem` · `lg→1.125rem` · `xl→1.25rem` · `2xl→1.5rem` · `3xl→1.875rem` · `4xl→2.25rem`
55
+
56
+ Unrecognised values pass through as raw CSS (e.g. `size="2em"` → `font-size:2em`).
57
+
58
+ ### Weight token map
59
+
60
+ `thin→100` · `light→300` · `normal→400` · `medium→500` · `semibold→600` · `bold→700` · `extrabold→800` · `black→900`
61
+
62
+ ### Spacing token map
63
+
64
+ `tight→-0.05em` · `normal→0em` · `wide→0.05em` · `wider→0.1em`
65
+
66
+ Unrecognised values pass through as raw CSS.
67
+
68
+ ### Color token map
69
+
70
+ `primary→var(--dm-color-primary)` · `secondary→var(--dm-color-secondary)` · `muted→var(--dm-text-muted)` ·
71
+ `danger→var(--dm-color-danger)` · `success→var(--dm-color-success)` · `warning→var(--dm-color-warning)` ·
72
+ `info→var(--dm-color-info)`
73
+
74
+ Unrecognised values pass through as raw CSS (hex, rgb, named CSS colours all work).
75
+
76
+ ### Font family map
77
+
78
+ `Georgia→"Georgia,serif"` · `Arial→"Arial,sans-serif"` · `Verdana→"Verdana,sans-serif"` ·
79
+ `Courier New→"'Courier New',monospace"` · `Times New Roman→"'Times New Roman',serif"` ·
80
+ `Trebuchet MS→"'Trebuchet MS',sans-serif"`
81
+
82
+ ### Transform map
83
+
84
+ `upper→uppercase` · `lower→lowercase` · `capitalize→capitalize` · `none→none`
85
+
86
+ ---
87
+
88
+ ## Processing Pipeline
89
+
90
+ `processTextBlocks()` is added to `server/services/markdown.js` and inserted between `[badge]` and `[button]`:
91
+
92
+ ```js
93
+ const withBadge = processBadgeBlocks(withTable);
94
+ const withText = processTextBlocks(withBadge); // ← new
95
+ const withButton = processButtonBlocks(withText);
96
+ ```
97
+
98
+ ### Implementation notes
99
+
100
+ - Uses `scrubCodeRegions` / `restore` pattern (same as all other shortcode processors) to skip fenced code blocks.
101
+ - **Flag detection:** `bold` and `italic` are flag attributes detected via regex on the raw attribute string - do NOT
102
+ use `parseShortcodeAttrs()` for these, as it only handles `key=value` pairs. Use `/\bbold\b/i.test(attrStr)` and
103
+ `/\bitalic\b/i.test(attrStr)`.
104
+ - **`bold` + `weight` precedence:** If both `bold` flag and `weight` attribute are present, `bold` wins - emit
105
+ `font-weight:700` and ignore `weight`.
106
+ - **`class` and `id` escaping:** Values from `class` and `id` attributes must be passed through `escapeAttr()` before
107
+ being written into the HTML output.
108
+ - **Inner content:** The shortcode body passes through `marked` and then `sanitize-html` downstream - no extra escaping
109
+ needed in the processor itself.
110
+
111
+ No changes needed to sanitize-html config - `style`, `class`, and `id` are already whitelisted via
112
+ `'*': ['class', 'id', 'style', 'data-*']`.
113
+
114
+ ---
115
+
116
+ ## Admin Insert Menu
117
+
118
+ ### markdown-toolbar.js changes
119
+
120
+ 1. Register a `text-style` SVG icon in `registerIcons()`.
121
+ 2. Add `{label: 'Text', icon: 'text-style', action: 'text'}` to the Insert dropdown items array between
122
+ `{label: 'Tabs', ...}` and `{label: 'Timeline', ...}`.
123
+ 3. Add `} else if (action === 'text') { ... }` inside the existing `executeAction()` function's `else if` chain - this
124
+ is where the modal is opened. **There is no `onText` callback and no `page-editor.js` change needed.** All
125
+ insert-action modals live directly inside `executeAction()` in `markdown-toolbar.js`.
126
+
127
+ ### Modal: "Style Text" (size `sm`)
128
+
129
+ Opened from the `action === 'text'` branch in `executeAction()`. Controls:
130
+
131
+ | Field | Control | Notes |
132
+ |------------|---------------------------|--------------------------------------------------------------------------|
133
+ | Content | `<input type="text">` | Pre-filled with any currently selected editor text |
134
+ | Size | `<select>` | Blank (default) + xs/sm/base/lg/xl/2xl/3xl/4xl |
135
+ | Weight | `<select>` | Blank (default) + thin/light/normal/medium/semibold/bold/extrabold/black |
136
+ | Bold | `<input type="checkbox">` | Shorthand - disables the Weight select when checked |
137
+ | Italic | `<input type="checkbox">` | |
138
+ | Colour | `<input type="text">` | Placeholder lists token names; accepts any CSS colour |
139
+ | Font | `<select>` | Blank (default) + 6 web-safe fonts |
140
+ | Transform | `<select>` | Blank (default) + uppercase/lowercase/capitalise/none |
141
+ | Decoration | `<select>` | Blank (default) + underline/line-through/none |
142
+ | Spacing | `<select>` | Blank (default) + tight/normal/wide/wider |
143
+ | CSS Class | `<input type="text">` | Optional |
144
+ | ID | `<input type="text">` | Optional |
145
+
146
+ **Live preview:** A wrapping `<div>` containing a `<span>` that updates in real time as controls change. Styles are
147
+ applied directly to the inner `<span>` to faithfully represent the actual rendered element (inline context, not block).
148
+
149
+ **Insert button:** Builds the shortcode string from only non-blank/non-default values, calls
150
+ `insertAtCursor(ta, snippet)`, closes the modal.
151
+
152
+ ---
153
+
154
+ ## Files Changed
155
+
156
+ | File | Change |
157
+ |------------------------------------|-------------------------------------------------------------------------------------------------------------------|
158
+ | `server/services/markdown.js` | Add `processTextBlocks()`, insert into pipeline between `withBadge` and `withButton` |
159
+ | `admin/js/lib/markdown-toolbar.js` | Register `text-style` icon, add Insert menu entry, add `action === 'text'` branch in `executeAction()` with modal |
160
+ | `docs/markdown-shortcodes.md` | Document new shortcode |
161
+
162
+ ---
163
+
164
+ ## Notes
165
+
166
+ - `[text]` is safe to nest inside `[card]`, `[slideover]`, `[grid]`, `[hero]`, etc.
167
+ - No client-side JS required - output is a plain `<span>` with inline styles, works in SSR.
168
+ - The modal is the canonical entry point; users can also write the shortcode by hand.
@@ -0,0 +1,315 @@
1
+ # Card Builder - Design Spec
2
+
3
+ **Date:** 2026-04-05
4
+ **Status:** Approved
5
+
6
+ ---
7
+
8
+ ## Overview
9
+
10
+ Enhance the page editor's card shortcode with an interactive visual builder dialog and significantly expand the `[card]`
11
+ shortcode to support 33 layout templates (27 Tier 1 attribute-driven + 6 Tier 2 sub-tag structured), 6 style variants,
12
+ and 14 gradient presets. The builder is a modal UI that generates a shortcode string and inserts it into the markdown
13
+ editor at the cursor position. No new API routes or database changes are required.
14
+
15
+ ---
16
+
17
+ ## Files
18
+
19
+ | File | Change |
20
+ |----------------------------------------|----------------------------------------------------------|
21
+ | `admin/js/lib/card-builder.js` | **New** - self-contained builder module |
22
+ | `admin/js/templates/card-builder.html` | **New** - builder dialog template |
23
+ | `admin/js/views/page-editor.js` | **Modified** - wire `toolbar.onCard()` |
24
+ | `server/services/markdown.js` | **Modified** - extend `processCardBlocks` for 33 layouts |
25
+ | `public/css/site.css` | **Modified** - 6 variants, 14 gradients, layout CSS |
26
+
27
+ ---
28
+
29
+ ## Architecture
30
+
31
+ **Approach:** Dedicated `card-builder.js` module (Option A).
32
+
33
+ **Flow:**
34
+
35
+ 1. User clicks **Card** in the markdown toolbar
36
+ 2. `toolbar.onCard()` fires → `CardBuilder.open(textarea)` called
37
+ 3. Modal dialog opens with layout picker, style swatches, dynamic fields, live preview
38
+ 4. User configures card visually - preview updates in real time
39
+ 5. User clicks **Insert Card** → shortcode string inserted at cursor → modal closes
40
+ 6. On save/preview, `processCardBlocks()` in `markdown.js` renders shortcode to HTML
41
+
42
+ The builder is completely decoupled from the editor. It receives a textarea reference on open and writes a shortcode
43
+ string back on insert. It has no knowledge of the editor's internal state.
44
+
45
+ ---
46
+
47
+ ## Shortcode Grammar
48
+
49
+ ### Universal attributes (all layouts)
50
+
51
+ | Attribute | Values | Notes |
52
+ |---------------|---------------------------------------------------|---------------------------------------------------------------|
53
+ | `layout` | 33 layout keys | Routes to correct renderer. Omit for `header-body` (default). |
54
+ | `title` | string | Header title where applicable |
55
+ | `subtitle` | string | Secondary line beneath title |
56
+ | `icon` | string | Domma icon name |
57
+ | `icon-layout` | `inline` \| `stacked` | Icon position relative to title |
58
+ | `variant` | `clean` `gradient` `glass` `accent` `dark` `glow` | Visual style |
59
+ | `gradient` | See gradient presets | Only used when `variant="gradient"` |
60
+ | `hover` | flag | Adds lift effect on hover |
61
+ | `collapsible` | `"true"` | Toggleable body via header click |
62
+ | `image` | URL | Image source for image-based layouts |
63
+ | `footer` | string | Simple text footer |
64
+ | `class` | string | Extra CSS classes |
65
+ | `id` | string | Anchor ID |
66
+
67
+ ### Layout-specific attributes
68
+
69
+ | Attribute | Layouts | Purpose |
70
+ |----------------|---------------------------|-------------------------------------------|
71
+ | `value` | stat-metric | Big display value |
72
+ | `delta` | stat-metric | Change indicator e.g. `↑ 12.4%` |
73
+ | `progress` | progress-goal | Integer 0-100 for progress bar fill |
74
+ | `price` | pricing | Price string e.g. `£29` |
75
+ | `period` | pricing | Billing period label |
76
+ | `lang` | code-snippet | Language label for syntax highlight badge |
77
+ | `filename` | file-document | Display filename |
78
+ | `filesize` | file-document | Size label e.g. `2.4 MB` |
79
+ | `filetype` | file-document | Extension badge e.g. `PDF` |
80
+ | `rating` | rating-review | Integer 1-5 for star display |
81
+ | `duration` | video-media | Time label e.g. `4:32` |
82
+ | `address` | location-map | Address line beneath map placeholder |
83
+ | `step` | step-numbered | Step number |
84
+ | `badge` | corner-badge, badge-band | Badge label text |
85
+ | `tags` | avatar-profile, tag-cloud | Comma-separated pill labels |
86
+ | `callout-type` | callout | `info` `warn` `success` `error` |
87
+
88
+ ### Sub-tags (Tier 2 layouts)
89
+
90
+ ```
91
+ [before]...[/before] → before-after (left column)
92
+ [after]...[/after] → before-after (right column)
93
+ [feature]...[/feature] → pricing, feature-comparison (repeating rows)
94
+ [activity user="..." action="..." time="..."] → activity-feed
95
+ [milestone done]...[/milestone] → progress-goal
96
+ ```
97
+
98
+ ---
99
+
100
+ ## The 33 Layouts
101
+
102
+ ### Tier 1 - Attribute-driven (27 layouts, body is plain Markdown)
103
+
104
+ | Key | Description |
105
+ |-------------------------|----------------------------------------------------------------------|
106
+ | `basic` | Body only, no header |
107
+ | `header-body` | Header + body (default) |
108
+ | `header-body-footer` | Header + body + footer |
109
+ | `no-header-footer` | Body + footer, no header |
110
+ | `icon-top` | Icon centred above title (stacked) |
111
+ | `icon-inline` | Icon beside title in flex row |
112
+ | `image-top` | Image at top, content below |
113
+ | `image-overlay` | Image with title overlaid via gradient scrim |
114
+ | `thumb-left` | Narrow image strip left, content right |
115
+ | `thumb-right` | Narrow image strip right, content left |
116
+ | `wide-left-image` | Wide image left, content right |
117
+ | `full-bg` | Full dark/image background card |
118
+ | `split-half` | Colour/image left half, dark content right half |
119
+ | `avatar-profile` | Circular avatar, name, role, tag pills |
120
+ | `stat-metric` | Large value, label, delta, progress bar |
121
+ | `quote-testimonial` | Quote marks, italic text, avatar attribution |
122
+ | `callout` | Left accent stripe + icon (info/warn/success/error) |
123
+ | `video-media` | Thumbnail with play button + duration badge |
124
+ | `location-map` | Grid map placeholder + address |
125
+ | `step-numbered` | Ghost large number + step badge |
126
+ | `corner-badge` | Badge pinned top-right, icon, centred title |
127
+ | `badge-band` | Gradient band with badge + icon, then content |
128
+ | `glass-gradient-border` | Multi-stop gradient border ring on frosted glass |
129
+ | `rating-review` | Stars, italic review, avatar attribution + verified |
130
+ | `tag-cloud` | Heading + wrapped coloured pill tags |
131
+ | `timeline-entry` | Date, dot, vertical line, title, text, tag |
132
+ | `code-snippet` | Body is raw code (no sub-tags); `lang` attribute sets language badge |
133
+
134
+ ### Tier 2 - Sub-tag structured (6 layouts, body uses named sub-tags)
135
+
136
+ | Key | Sub-tags used |
137
+ |----------------------|------------------------------------------------------------------------|
138
+ | `before-after` | `[before]` / `[after]` |
139
+ | `pricing` | `[feature]` list |
140
+ | `feature-comparison` | `[feature]` with ✓/✗ values |
141
+ | `activity-feed` | `[activity]` items |
142
+ | `progress-goal` | `[milestone]` items |
143
+ | `file-document` | Attributes only - any body content is silently ignored by the renderer |
144
+
145
+ ---
146
+
147
+ ## 6 Style Variants
148
+
149
+ | Variant | Class | Hover Effect |
150
+ |------------|---------------------|-----------------------------------------------|
151
+ | `clean` | `.dm-card-clean` | translateY(-4px) + shadow deepen |
152
+ | `gradient` | `.dm-card-gradient` | translateY(-5px) + violet shadow bloom |
153
+ | `glass` | `.dm-card-glass` | translateY(-4px) + backdrop lightens |
154
+ | `accent` | `.dm-card-accent` | translateY(-3px) + border deepens + shadow |
155
+ | `dark` | `.dm-card-dark` | translateY(-4px) + scale(1.012) + deep shadow |
156
+ | `glow` | `.dm-card-glow` | ring glow expands + border brightens |
157
+
158
+ Utility: `.card-hover` (opt-in lift, no variant needed), `.card-collapsible` (header toggles body with `max-height`
159
+ transition).
160
+
161
+ **Collapsible wiring:** When `collapsible="true"` is parsed, `processCardBlocks` adds `.card-collapsible` to the root
162
+ element and `data-collapsible="true"`. `site.js` delegates a click handler on `.card-collapsible .card-header` that
163
+ toggles `.is-collapsed` on the root. `.is-collapsed .card-body` has `max-height: 0; overflow: hidden` with a CSS
164
+ transition. The header receives a CSS-only chevron via `::after` that rotates on `.is-collapsed`.
165
+
166
+ ---
167
+
168
+ ## 14 Gradient Presets
169
+
170
+ Applied via `gradient="name"` when `variant="gradient"`. Also controls the coloured element in `badge-band` (the top
171
+ band), `pricing` (the header), `step-numbered` (the background strip), and `split-half` (the left half) - all Tier 1
172
+ layouts. The `gradient` attribute is ignored on all other layouts.
173
+
174
+ | Name | Stops |
175
+ |------------|---------------------------------|
176
+ | `indigo` | `#6366f1 → #8b5cf6` (default) |
177
+ | `ocean` | `#0891b2 → #2563eb` |
178
+ | `sunset` | `#f59e0b → #ef4444 → #ec4899` |
179
+ | `forest` | `#10b981 → #0d9488` |
180
+ | `rose` | `#fb7185 → #e11d48` |
181
+ | `midnight` | `#1e1b4b → #4338ca` |
182
+ | `aurora` | `#06b6d4 → #6366f1 → #a855f7` |
183
+ | `fire` | `#ef4444 → #f97316 → #fbbf24` |
184
+ | `lagoon` | `#06b6d4 → #0e7490` |
185
+ | `dusk` | `#7c3aed → #db2777` |
186
+ | `lime` | `#84cc16 → #10b981` |
187
+ | `gold` | `#f59e0b → #b45309` |
188
+ | `arctic` | `#bae6fd → #e0f2fe` (dark text) |
189
+ | `slate` | `#475569 → #1e293b` |
190
+
191
+ ---
192
+
193
+ ## Card Builder Dialog (card-builder.js)
194
+
195
+ ### Structure
196
+
197
+ - **Left panel (280px):** Layout dropdown (grouped, with thumbnail previews) → Style swatches → dynamic fields (change
198
+ per layout) → Options row (Collapsible / Hover toggles)
199
+ - **Right panel (flex):** Live preview card → Shortcode output box
200
+ - **Footer:** Status line (layout + style) + Cancel / Insert Card buttons
201
+
202
+ ### Dynamic fields per layout tier
203
+
204
+ - **All layouts:** Title, Body textarea
205
+ - **Icon layouts:** Icon input + Browse Icons button (opens icon picker overlay) + icon-layout toggle
206
+ - **Image layouts:** Image URL + Browse Media button (opens existing media modal)
207
+ - **Tier 2 layouts:** Structured field set appropriate to the layout (e.g., price + period fields for pricing; step
208
+ number for step-numbered)
209
+ - **Gradient variant:** Circle swatch picker (14 presets) appears below style swatches
210
+ - **Glass variant:** Warning note - "Glass looks best inside a coloured [hero] or [card] section."
211
+
212
+ ### Icon picker
213
+
214
+ Overlay panel with search input + grid of all Domma icons. Click to select → populates icon field + closes overlay.
215
+ Confirm button shows selected icon name.
216
+
217
+ ### Media browser
218
+
219
+ `CardBuilder` accepts an optional `onMediaBrowse` callback in its options object:
220
+ `CardBuilder.open(textarea, { onMediaBrowse })`. `page-editor.js` provides this callback, which opens the existing media
221
+ picker modal and resolves with the selected URL. This keeps `card-builder.js` decoupled from the media system.
222
+
223
+ ### Live preview
224
+
225
+ The builder ships a lightweight **client-side preview renderer** (inline in `card-builder.js`). It builds DOM nodes
226
+ directly using `document.createElement` and the same CSS classes that `processCardBlocks` outputs (e.g. `.card`,
227
+ `.dm-card-gradient`, `.card-header`, `.card-body`). It does **not** call any API endpoint. For Tier 2 layouts the
228
+ preview renders a simplified representative structure - e.g. pricing shows a static two-feature list rather than parsing
229
+ `[feature]` sub-tags. This is clearly labelled in the preview panel as "Simplified preview - full render on save."
230
+
231
+ ### Shortcode generator
232
+
233
+ Builds the shortcode string from current state. Displayed in the snippet box and used on Insert.
234
+
235
+ ---
236
+
237
+ ## CSS (site.css)
238
+
239
+ ### New rules added
240
+
241
+ - `.dm-card-{variant}` - 6 variant base + hover rules
242
+ - `.card-gradient-{name}` - 14 gradient classes (used on header/band elements)
243
+ - `.card-layout-{key}` - structural CSS for layouts that need it (flex, grid, image sizing)
244
+ - `.card-img-top`, `.card-img-left`, `.card-img-right` - image containers using `background-image` + `cover`
245
+ - Responsive: side-image layouts stack at `480px`
246
+ - Dark variant + image: auto dark scrim overlay on image containers
247
+
248
+ ### toolbar.onCard() integration
249
+
250
+ `markdown-toolbar.js` already exposes `toolbar.onCard(cb)` - when the Card button is clicked, it calls `cb(textarea)` if
251
+ registered, otherwise falls back to a dumb snippet insert. In `page-editor.js` `onMount`, after the toolbar is
252
+ initialised:
253
+
254
+ ```js
255
+ toolbar.onCard((ta) => {
256
+ CardBuilder.open(ta, {
257
+ onMediaBrowse: () => openMediaPicker(), // returns Promise<url>
258
+ });
259
+ });
260
+ ```
261
+
262
+ `CardBuilder.open(textarea, options)` is the sole public API of `card-builder.js`. It opens the dialog, and on Insert
263
+ calls:
264
+
265
+ ```js
266
+ const snippet = buildShortcode(state);
267
+ const start = textarea.selectionStart;
268
+ textarea.value = textarea.value.slice(0, start) + snippet + textarea.value.slice(textarea.selectionEnd);
269
+ textarea.dispatchEvent(new Event('input', { bubbles: true }));
270
+ textarea.focus();
271
+ ```
272
+
273
+ ### Backwards compatibility
274
+
275
+ All existing shortcodes continue to work unchanged. `processCardBlocks` checks for `layout` attribute; if absent, falls
276
+ back to the existing rendering path.
277
+
278
+ ---
279
+
280
+ ## Image handling
281
+
282
+ - All image containers use `background-image: url(...)` + `background-size: cover` + `background-position: center`
283
+ - Fallback when no image provided: themed gradient placeholder matching current variant
284
+ - Side-image layouts (`thumb-left`, `thumb-right`, `wide-left-image`, `split-half`) stack vertically at `≤480px`
285
+
286
+ ---
287
+
288
+ ## Shortcode Examples
289
+
290
+ ```markdown
291
+ [card layout="image-top" title="Getting Started" image="/media/hero.jpg"
292
+ variant="gradient" gradient="ocean" hover footer="5 min read"]
293
+ A short description below the image.
294
+ [/card]
295
+
296
+ [card layout="pricing" title="Pro" price="£29" period="per month"
297
+ variant="gradient" gradient="indigo"]
298
+ [feature]Unlimited pages[/feature]
299
+ [feature]All plugins[/feature]
300
+ [feature]Priority support[/feature]
301
+ [/card]
302
+
303
+ [card layout="callout" callout-type="info" icon="bulb" title="Good to know"]
304
+ This tip will save you time.
305
+ [/card]
306
+
307
+ [card layout="stat-metric" title="Monthly Revenue" value="£24,980"
308
+ delta="↑ 12.4%" variant="clean" hover]
309
+ [/card]
310
+
311
+ [card layout="before-after" title="Why switch?"]
312
+ [before]Manual updates · No versioning · Dev dependency[/before]
313
+ [after]Auto deploy · Full history · Editors own it[/after]
314
+ [/card]
315
+ ```