domma-cms 0.1.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 (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +469 -0
  3. package/admin/css/admin.css +1123 -0
  4. package/admin/index.html +72 -0
  5. package/admin/js/api.js +210 -0
  6. package/admin/js/app.js +270 -0
  7. package/admin/js/config/sidebar-config.js +107 -0
  8. package/admin/js/lib/card.js +63 -0
  9. package/admin/js/lib/image-editor.js +869 -0
  10. package/admin/js/lib/markdown-toolbar.js +421 -0
  11. package/admin/js/templates/dashboard.html +50 -0
  12. package/admin/js/templates/documentation.html +237 -0
  13. package/admin/js/templates/layouts.html +11 -0
  14. package/admin/js/templates/login.html +58 -0
  15. package/admin/js/templates/media.html +16 -0
  16. package/admin/js/templates/navigation.html +50 -0
  17. package/admin/js/templates/page-editor.html +126 -0
  18. package/admin/js/templates/pages.html +18 -0
  19. package/admin/js/templates/plugins.html +12 -0
  20. package/admin/js/templates/settings.html +190 -0
  21. package/admin/js/templates/tutorials.html +233 -0
  22. package/admin/js/templates/user-editor.html +12 -0
  23. package/admin/js/templates/users.html +10 -0
  24. package/admin/js/views/dashboard.js +48 -0
  25. package/admin/js/views/documentation.js +12 -0
  26. package/admin/js/views/index.js +33 -0
  27. package/admin/js/views/layouts.js +49 -0
  28. package/admin/js/views/login.js +254 -0
  29. package/admin/js/views/media.js +240 -0
  30. package/admin/js/views/navigation.js +152 -0
  31. package/admin/js/views/page-editor.js +479 -0
  32. package/admin/js/views/pages.js +64 -0
  33. package/admin/js/views/plugins.js +100 -0
  34. package/admin/js/views/settings.js +64 -0
  35. package/admin/js/views/tutorials.js +12 -0
  36. package/admin/js/views/user-editor.js +88 -0
  37. package/admin/js/views/users.js +73 -0
  38. package/bin/cli.js +334 -0
  39. package/config/auth.json +20 -0
  40. package/config/content.json +10 -0
  41. package/config/navigation.json +63 -0
  42. package/config/plugins.json +47 -0
  43. package/config/presets.json +34 -0
  44. package/config/server.json +6 -0
  45. package/config/site.json +33 -0
  46. package/package.json +67 -0
  47. package/plugins/back-to-top/admin/templates/back-to-top-settings.html +55 -0
  48. package/plugins/back-to-top/admin/views/back-to-top-settings.js +44 -0
  49. package/plugins/back-to-top/config.js +10 -0
  50. package/plugins/back-to-top/plugin.js +24 -0
  51. package/plugins/back-to-top/plugin.json +36 -0
  52. package/plugins/back-to-top/public/inject-body.html +105 -0
  53. package/plugins/cookie-consent/admin/templates/cookie-consent-settings.html +113 -0
  54. package/plugins/cookie-consent/admin/views/cookie-consent-settings.js +73 -0
  55. package/plugins/cookie-consent/config.js +30 -0
  56. package/plugins/cookie-consent/plugin.js +24 -0
  57. package/plugins/cookie-consent/plugin.json +36 -0
  58. package/plugins/cookie-consent/public/inject-body.html +69 -0
  59. package/plugins/custom-css/admin/templates/custom-css.html +17 -0
  60. package/plugins/custom-css/admin/views/custom-css.js +35 -0
  61. package/plugins/custom-css/config.js +1 -0
  62. package/plugins/custom-css/data/custom.css +0 -0
  63. package/plugins/custom-css/plugin.js +63 -0
  64. package/plugins/custom-css/plugin.json +32 -0
  65. package/plugins/custom-css/public/inject-head.html +1 -0
  66. package/plugins/domma-effects/admin/templates/domma-effects.html +488 -0
  67. package/plugins/domma-effects/admin/views/domma-effects.js +56 -0
  68. package/plugins/domma-effects/config.js +9 -0
  69. package/plugins/domma-effects/plugin.js +22 -0
  70. package/plugins/domma-effects/plugin.json +36 -0
  71. package/plugins/domma-effects/public/celebrations/core/canvas.js +111 -0
  72. package/plugins/domma-effects/public/celebrations/core/particles.js +144 -0
  73. package/plugins/domma-effects/public/celebrations/core/physics.js +166 -0
  74. package/plugins/domma-effects/public/celebrations/index.js +535 -0
  75. package/plugins/domma-effects/public/celebrations/themes/christmas.js +1805 -0
  76. package/plugins/domma-effects/public/celebrations/themes/guy-fawkes.js +1477 -0
  77. package/plugins/domma-effects/public/celebrations/themes/halloween.js +1837 -0
  78. package/plugins/domma-effects/public/celebrations/themes/st-andrews.js +1175 -0
  79. package/plugins/domma-effects/public/celebrations/themes/st-davids.js +1258 -0
  80. package/plugins/domma-effects/public/celebrations/themes/st-georges.js +1754 -0
  81. package/plugins/domma-effects/public/celebrations/themes/st-patricks.js +1290 -0
  82. package/plugins/domma-effects/public/celebrations/themes/valentines.js +1361 -0
  83. package/plugins/domma-effects/public/inject-body.html +268 -0
  84. package/plugins/example-analytics/admin/templates/analytics.html +10 -0
  85. package/plugins/example-analytics/admin/views/analytics.js +51 -0
  86. package/plugins/example-analytics/config.js +6 -0
  87. package/plugins/example-analytics/plugin.js +58 -0
  88. package/plugins/example-analytics/plugin.json +27 -0
  89. package/plugins/example-analytics/public/inject-body.html +13 -0
  90. package/plugins/example-analytics/public/inject-head.html +1 -0
  91. package/plugins/example-analytics/stats.json +1 -0
  92. package/plugins/form-builder/admin/templates/form-editor.html +158 -0
  93. package/plugins/form-builder/admin/templates/form-settings.html +29 -0
  94. package/plugins/form-builder/admin/templates/form-submissions.html +30 -0
  95. package/plugins/form-builder/admin/templates/forms-list.html +17 -0
  96. package/plugins/form-builder/admin/views/form-editor.js +817 -0
  97. package/plugins/form-builder/admin/views/form-settings.js +38 -0
  98. package/plugins/form-builder/admin/views/form-submissions.js +295 -0
  99. package/plugins/form-builder/admin/views/forms-list.js +164 -0
  100. package/plugins/form-builder/config.js +9 -0
  101. package/plugins/form-builder/data/forms/contact-details.json +63 -0
  102. package/plugins/form-builder/data/forms/contact.json +52 -0
  103. package/plugins/form-builder/data/submissions/contact-details.json +1 -0
  104. package/plugins/form-builder/data/submissions/contact.json +14 -0
  105. package/plugins/form-builder/email.js +103 -0
  106. package/plugins/form-builder/plugin.js +454 -0
  107. package/plugins/form-builder/plugin.json +56 -0
  108. package/plugins/form-builder/public/inject-body.html +270 -0
  109. package/plugins/form-builder/public/inject-head.html +42 -0
  110. package/public/css/site.css +189 -0
  111. package/public/js/site.js +109 -0
  112. package/scripts/copy-domma.js +48 -0
  113. package/scripts/fresh.js +41 -0
  114. package/scripts/reset.js +124 -0
  115. package/scripts/seed.js +666 -0
  116. package/scripts/setup.js +263 -0
  117. package/server/config.js +56 -0
  118. package/server/middleware/auth.js +97 -0
  119. package/server/routes/api/auth.js +116 -0
  120. package/server/routes/api/layouts.js +25 -0
  121. package/server/routes/api/media.js +93 -0
  122. package/server/routes/api/navigation.js +37 -0
  123. package/server/routes/api/pages.js +118 -0
  124. package/server/routes/api/plugins.js +46 -0
  125. package/server/routes/api/settings.js +25 -0
  126. package/server/routes/api/users.js +110 -0
  127. package/server/routes/public.js +108 -0
  128. package/server/server.js +169 -0
  129. package/server/services/content.js +298 -0
  130. package/server/services/images.js +334 -0
  131. package/server/services/markdown.js +297 -0
  132. package/server/services/plugins.js +246 -0
  133. package/server/services/renderer.js +80 -0
  134. package/server/services/users.js +212 -0
  135. package/server/templates/page.html +78 -0
@@ -0,0 +1,666 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Domma CMS — Seed Demo Content
4
+ * Creates sample pages and updates navigation.
5
+ * Safe to run multiple times — overwrites seed paths only.
6
+ * Run: npm run seed
7
+ */
8
+ import {mkdir, writeFile} from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import {fileURLToPath} from 'node:url';
11
+
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ const ROOT = path.resolve(__dirname, '..');
14
+
15
+ const PAGES_DIR = path.join(ROOT, 'content', 'pages');
16
+ const NAV_CFG = path.join(ROOT, 'config', 'navigation.json');
17
+
18
+ const now = new Date().toISOString();
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Seed navigation
22
+ // ---------------------------------------------------------------------------
23
+
24
+ const SEED_NAV = {
25
+ brand: { text: 'My Site', logo: null, url: '/' },
26
+ items: [
27
+ { text: 'Home', url: '/', icon: 'home' },
28
+ { text: 'About', url: '/about', icon: 'info' },
29
+ { text: 'Blog', url: '/blog', icon: 'book-open' },
30
+ {text: 'Contact', url: '/contact', icon: 'mail'},
31
+ {
32
+ text: 'Resources', url: '/resources', icon: 'book-open',
33
+ items: [
34
+ {text: 'Overview', url: '/resources', icon: 'grid'},
35
+ {text: 'Typography', url: '/resources/typography', icon: 'type'},
36
+ {text: 'Grid System', url: '/resources/grid', icon: 'layout'},
37
+ {text: 'Cards', url: '/resources/cards', icon: 'credit-card'},
38
+ {text: 'Shortcode Reference', url: '/resources/shortcodes', icon: 'code'}
39
+ ]
40
+ }
41
+ ],
42
+ variant: 'dark',
43
+ position: 'sticky'
44
+ };
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Page definitions
48
+ // ---------------------------------------------------------------------------
49
+
50
+ const PAGES = [
51
+ {
52
+ file: 'index.md',
53
+ fm: {
54
+ title: 'Welcome', slug: 'index',
55
+ description: 'Your new website, powered by Domma CMS',
56
+ layout: 'default', status: 'published',
57
+ sortOrder: 1, showInNav: false, sidebar: false,
58
+ seo: { title: 'Welcome', description: 'Your new website, powered by Domma CMS' },
59
+ createdAt: now, updatedAt: now
60
+ },
61
+ body: `# Welcome
62
+
63
+ This is your new website, powered by **Domma CMS**.
64
+
65
+ Edit this page from the [admin panel](/admin/), or modify \`content/pages/index.md\` directly.
66
+
67
+ ## What you can do
68
+
69
+ - **Write pages** — create and publish content in Markdown
70
+ - **Manage navigation** — build your site's menu from the admin panel
71
+ - **Upload media** — attach images and files to your pages
72
+ - **Choose a theme** — pick from 16 built-in colour schemes
73
+
74
+ [Sign in to the admin panel →](/admin/)
75
+ `
76
+ },
77
+ {
78
+ file: 'about.md',
79
+ fm: {
80
+ title: 'About', slug: 'about',
81
+ description: 'Learn more about us',
82
+ layout: 'default', status: 'published',
83
+ sortOrder: 2, showInNav: true, sidebar: false,
84
+ seo: { title: 'About', description: 'Learn more about us' },
85
+ createdAt: now, updatedAt: now
86
+ },
87
+ body: `# About
88
+
89
+ This is the About page — tell your visitors who you are, what you do, and why it matters.
90
+
91
+ ## Our story
92
+
93
+ Replace this content with your own. Edit it any time from the [admin panel](/admin/).
94
+
95
+ ## What we do
96
+
97
+ Add your services, mission statement, or team information here.
98
+ `
99
+ },
100
+ {
101
+ file: 'contact.md',
102
+ fm: {
103
+ title: 'Contact', slug: 'contact',
104
+ description: 'Get in touch',
105
+ layout: 'default', status: 'published',
106
+ sortOrder: 4, showInNav: true, sidebar: false,
107
+ seo: { title: 'Contact', description: 'Get in touch with us' },
108
+ createdAt: now, updatedAt: now
109
+ },
110
+ body: `# Contact
111
+
112
+ Get in touch — we'd love to hear from you.
113
+
114
+ ## How to reach us
115
+
116
+ Replace this with your contact details, a form, or whatever works best for your site.
117
+
118
+ Edit this page from the [admin panel](/admin/).
119
+ `
120
+ },
121
+ {
122
+ file: path.join('blog', 'index.md'),
123
+ fm: {
124
+ title: 'Blog', slug: 'blog',
125
+ description: 'News, updates and articles',
126
+ layout: 'default', status: 'published',
127
+ sortOrder: 3, showInNav: true, sidebar: false,
128
+ seo: { title: 'Blog', description: 'News, updates and articles' },
129
+ createdAt: now, updatedAt: now
130
+ },
131
+ body: `# Blog
132
+
133
+ Welcome to the blog. Read on for articles, updates and news.
134
+
135
+ ---
136
+
137
+ - [Hello, World!](/blog/hello-world) — Your first post
138
+ `
139
+ },
140
+ {
141
+ file: path.join('blog', 'hello-world.md'),
142
+ fm: {
143
+ title: 'Hello, World!', slug: 'hello-world',
144
+ description: 'The first post on this site',
145
+ layout: 'default', status: 'published',
146
+ sortOrder: 1, showInNav: false, sidebar: false,
147
+ seo: { title: 'Hello, World!', description: 'The first post on this site' },
148
+ createdAt: now, updatedAt: now
149
+ },
150
+ body: `# Hello, World!
151
+
152
+ Welcome to your first blog post, created by the Domma CMS seed script.
153
+
154
+ Edit or delete this from the [admin panel](/admin/), then start writing your own content.
155
+
156
+ ## Writing in Markdown
157
+
158
+ Domma CMS uses **Markdown** for all page content:
159
+
160
+ - **Bold** with \`**double asterisks**\`
161
+ - *Italic* with \`*single asterisks*\`
162
+ - \`Inline code\` with backticks
163
+ - [Links](https://example.com) with \`[text](url)\`
164
+
165
+ > Blockquotes with \`>\`
166
+
167
+ \`\`\`
168
+ Code blocks with triple backticks
169
+ \`\`\`
170
+
171
+ Happy writing!
172
+ `
173
+ },
174
+
175
+ // ----- Resources -----
176
+
177
+ {
178
+ file: path.join('resources', 'index.md'),
179
+ fm: {
180
+ title: 'Resources', slug: 'resources',
181
+ description: 'Reference pages showing the Domma CMS kit — typography, grid, cards, and shortcodes.',
182
+ layout: 'default', status: 'published',
183
+ sortOrder: 10, showInNav: false, sidebar: false,
184
+ seo: {title: 'Resources', description: 'Domma CMS component and shortcode reference'},
185
+ createdAt: now, updatedAt: now
186
+ },
187
+ body: `# Resources
188
+
189
+ Reference pages for content authors and developers working with Domma CMS.
190
+
191
+ [grid cols="2" gap="4"]
192
+ [col]
193
+ [card title="Typography"]
194
+ Headings, paragraphs, lists, blockquotes, inline code, and all standard Markdown elements.
195
+
196
+ [Read more →](/resources/typography)
197
+ [/card]
198
+ [/col]
199
+ [col]
200
+ [card title="Grid System"]
201
+ Equal columns, column spanning, gap sizes, and flexbox rows using the \`[grid]\`, \`[row]\`, and \`[col]\` shortcodes.
202
+
203
+ [Read more →](/resources/grid)
204
+ [/card]
205
+ [/col]
206
+ [col]
207
+ [card title="Cards"]
208
+ Card shortcode variants — basic, titled, collapsible, and cards inside grid layouts.
209
+
210
+ [Read more →](/resources/cards)
211
+ [/card]
212
+ [/col]
213
+ [col]
214
+ [card title="Shortcode Reference"]
215
+ Full reference for every shortcode supported in the editor, including all attributes and examples.
216
+
217
+ [Read more →](/resources/shortcodes)
218
+ [/card]
219
+ [/col]
220
+ [/grid]
221
+ `
222
+ },
223
+ {
224
+ file: path.join('resources', 'typography.md'),
225
+ fm: {
226
+ title: 'Typography', slug: 'typography',
227
+ description: 'Headings, paragraphs, lists, blockquotes, code, and all standard text elements.',
228
+ layout: 'default', status: 'published',
229
+ sortOrder: 11, showInNav: false, sidebar: false,
230
+ seo: {title: 'Typography — Resources', description: 'Typography reference for Domma CMS'},
231
+ createdAt: now, updatedAt: now
232
+ },
233
+ body: `# Typography
234
+
235
+ Everything you can express with standard Markdown in the Domma CMS editor.
236
+
237
+ ---
238
+
239
+ ## Headings
240
+
241
+ # Heading 1
242
+ ## Heading 2
243
+ ### Heading 3
244
+ #### Heading 4
245
+ ##### Heading 5
246
+ ###### Heading 6
247
+
248
+ ---
249
+
250
+ ## Paragraphs & Inline Styles
251
+
252
+ This is a regular paragraph. You can make text **bold**, _italic_, or ~~strikethrough~~. Combine them: **_bold and italic_**.
253
+
254
+ You can also write \`inline code\` using backticks.
255
+
256
+ ---
257
+
258
+ ## Blockquotes
259
+
260
+ > A blockquote stands out from body text and is useful for callouts, pull quotes, or attributed statements.
261
+
262
+ > Blockquotes can contain **inline formatting** and span multiple lines.
263
+
264
+ ---
265
+
266
+ ## Lists
267
+
268
+ ### Unordered
269
+
270
+ - First item
271
+ - Second item
272
+ - Nested item
273
+ - Another nested item
274
+ - Third item
275
+
276
+ ### Ordered
277
+
278
+ 1. Step one
279
+ 2. Step two
280
+ 3. Step three
281
+ 1. Sub-step
282
+ 2. Sub-step
283
+
284
+ ---
285
+
286
+ ## Code
287
+
288
+ Inline code uses single backticks: \`npm run dev\`
289
+
290
+ Fenced code blocks use triple backticks:
291
+
292
+ \`\`\`js
293
+ function greet(name) {
294
+ return \\\`Hello, \\\${name}!\\\`;
295
+ }
296
+ \`\`\`
297
+
298
+ ---
299
+
300
+ ## Tables
301
+
302
+ | Column A | Column B | Column C |
303
+ |----------|----------|----------|
304
+ | Cell 1 | Cell 2 | Cell 3 |
305
+ | Cell 4 | Cell 5 | Cell 6 |
306
+
307
+ ---
308
+
309
+ ← [Back to Resources](/resources)
310
+ `
311
+ },
312
+ {
313
+ file: path.join('resources', 'grid.md'),
314
+ fm: {
315
+ title: 'Grid System', slug: 'grid',
316
+ description: 'Equal columns, column spanning, gap sizes, and flexbox rows using grid shortcodes.',
317
+ layout: 'default', status: 'published',
318
+ sortOrder: 12, showInNav: false, sidebar: false,
319
+ seo: {title: 'Grid System — Resources', description: 'Domma CMS grid shortcode reference'},
320
+ createdAt: now, updatedAt: now
321
+ },
322
+ body: `# Grid System
323
+
324
+ Domma uses native CSS Grid via shortcodes. Use \`[grid]\`, \`[row]\`, and \`[col]\` in the editor — no HTML needed.
325
+
326
+ ---
327
+
328
+ ## Equal Columns
329
+
330
+ ### 2 Columns
331
+
332
+ [grid cols="2" gap="4"]
333
+ [col]
334
+ **Left column**
335
+ Each \`[col]\` fills one track of the grid automatically.
336
+ [/col]
337
+ [col]
338
+ **Right column**
339
+ No extra attributes needed for equal widths.
340
+ [/col]
341
+ [/grid]
342
+
343
+ ### 3 Columns
344
+
345
+ [grid cols="3" gap="4"]
346
+ [col]**One** — first of three.[/col]
347
+ [col]**Two** — second of three.[/col]
348
+ [col]**Three** — third of three.[/col]
349
+ [/grid]
350
+
351
+ ### 4 Columns
352
+
353
+ [grid cols="4" gap="3"]
354
+ [col]Alpha[/col]
355
+ [col]Beta[/col]
356
+ [col]Gamma[/col]
357
+ [col]Delta[/col]
358
+ [/grid]
359
+
360
+ ---
361
+
362
+ ## Column Spanning
363
+
364
+ Use \`span="N"\` on a \`[col]\` to make it span more than one track. Values must add up to \`cols\`.
365
+
366
+ ### 8 / 4 split
367
+
368
+ [grid cols="12" gap="4"]
369
+ [col span="8"]**span="8"** — main content area (two-thirds).[/col]
370
+ [col span="4"]**span="4"** — sidebar (one-third).[/col]
371
+ [/grid]
372
+
373
+ ### 6 / 6 (halves)
374
+
375
+ [grid cols="12" gap="4"]
376
+ [col span="6"]**span="6"** — left half.[/col]
377
+ [col span="6"]**span="6"** — right half.[/col]
378
+ [/grid]
379
+
380
+ ### 9 / 3
381
+
382
+ [grid cols="12" gap="4"]
383
+ [col span="9"]**span="9"** — wide column.[/col]
384
+ [col span="3"]**span="3"** — narrow aside.[/col]
385
+ [/grid]
386
+
387
+ ---
388
+
389
+ ## Gap Sizes
390
+
391
+ **gap="1"**
392
+ [grid cols="4" gap="1"]
393
+ [col]One[/col][col]Two[/col][col]Three[/col][col]Four[/col]
394
+ [/grid]
395
+
396
+ **gap="3"**
397
+ [grid cols="4" gap="3"]
398
+ [col]One[/col][col]Two[/col][col]Three[/col][col]Four[/col]
399
+ [/grid]
400
+
401
+ **gap="6"**
402
+ [grid cols="4" gap="6"]
403
+ [col]One[/col][col]Two[/col][col]Three[/col][col]Four[/col]
404
+ [/grid]
405
+
406
+ ---
407
+
408
+ ## Row (Flexbox)
409
+
410
+ \`[row]\` uses flexbox — columns share available space equally without specifying a count.
411
+
412
+ [row gap="4"]
413
+ [col]**Flex col 1**[/col]
414
+ [col]**Flex col 2**[/col]
415
+ [col]**Flex col 3**[/col]
416
+ [/row]
417
+
418
+ ---
419
+
420
+ ← [Back to Resources](/resources)
421
+ `
422
+ },
423
+ {
424
+ file: path.join('resources', 'cards.md'),
425
+ fm: {
426
+ title: 'Cards', slug: 'cards',
427
+ description: 'Card shortcode variants — basic, titled, collapsible, and cards in grid layouts.',
428
+ layout: 'default', status: 'published',
429
+ sortOrder: 13, showInNav: false, sidebar: false,
430
+ seo: {title: 'Cards — Resources', description: 'Domma CMS card shortcode reference'},
431
+ createdAt: now, updatedAt: now
432
+ },
433
+ body: `# Cards
434
+
435
+ The \`[card]\` shortcode wraps content in a styled card. Cards support full Markdown inside them, including other shortcodes.
436
+
437
+ ---
438
+
439
+ ## Basic Card (no header)
440
+
441
+ [card]
442
+ This is a basic card with no title. Useful for callout blocks or highlighted sections.
443
+
444
+ It supports **bold**, _italic_, and \`inline code\`.
445
+ [/card]
446
+
447
+ ---
448
+
449
+ ## Card with Title
450
+
451
+ [card title="Card Title"]
452
+ This card has a header. The \`title\` attribute sets the text in the card's top bar.
453
+ [/card]
454
+
455
+ ---
456
+
457
+ ## Collapsible Card
458
+
459
+ Add \`collapsible="true"\` to make the body toggle on header click. Starts collapsed.
460
+
461
+ [card title="Click to expand" collapsible="true"]
462
+ This content is hidden by default and revealed when the header is clicked.
463
+ [/card]
464
+
465
+ ---
466
+
467
+ ## Cards in a Grid
468
+
469
+ [grid cols="3" gap="4"]
470
+ [col]
471
+ [card title="Feature One"]
472
+ Describe the first feature here. One or two sentences works well in a three-column layout.
473
+ [/card]
474
+ [/col]
475
+ [col]
476
+ [card title="Feature Two"]
477
+ Cards in a grid automatically share the same height within a row.
478
+ [/card]
479
+ [/col]
480
+ [col]
481
+ [card title="Feature Three"]
482
+ Add a link if this feature has its own dedicated page.
483
+ [/card]
484
+ [/col]
485
+ [/grid]
486
+
487
+ ---
488
+
489
+ ## Grid Inside a Card
490
+
491
+ [card title="Two-column layout inside a card"]
492
+ [grid cols="2" gap="4"]
493
+ [col]
494
+ Use the left column for a description or introductory copy.
495
+ [/col]
496
+ [col]
497
+ Use the right column for a list or supplementary detail.
498
+
499
+ - Point A
500
+ - Point B
501
+ - Point C
502
+ [/col]
503
+ [/grid]
504
+ [/card]
505
+
506
+ ---
507
+
508
+ ← [Back to Resources](/resources)
509
+ `
510
+ },
511
+ {
512
+ file: path.join('resources', 'shortcodes.md'),
513
+ fm: {
514
+ title: 'Shortcode Reference', slug: 'shortcodes',
515
+ description: 'Full reference for every shortcode supported in the Domma CMS editor.',
516
+ layout: 'default', status: 'published',
517
+ sortOrder: 14, showInNav: false, sidebar: false,
518
+ seo: {title: 'Shortcode Reference — Resources', description: 'Complete shortcode reference for Domma CMS'},
519
+ createdAt: now, updatedAt: now
520
+ },
521
+ body: `# Shortcode Reference
522
+
523
+ Shortcodes extend Markdown with layout and component capabilities. Mix them freely with regular Markdown.
524
+
525
+ **Syntax:** \`[shortcode attribute="value"]…[/shortcode]\`
526
+
527
+ ---
528
+
529
+ ## [\`grid\`]
530
+
531
+ Creates a CSS Grid container.
532
+
533
+ | Attribute | Required | Description |
534
+ |-----------|----------|-------------|
535
+ | \`cols\` | Yes | Number of columns (1–12) |
536
+ | \`gap\` | No | Gap between cells (1–6) |
537
+ | \`class\` | No | Extra CSS classes |
538
+
539
+ [grid cols="3" gap="4"]
540
+ [col]**cols="3"**[/col]
541
+ [col]**gap="4"**[/col]
542
+ [col]**Equal widths**[/col]
543
+ [/grid]
544
+
545
+ ---
546
+
547
+ ## [\`row\`]
548
+
549
+ Flexbox row — columns share available width equally, no \`cols\` needed.
550
+
551
+ | Attribute | Required | Description |
552
+ |-----------|----------|-------------|
553
+ | \`gap\` | No | Gap between columns (1–6) |
554
+ | \`class\` | No | Extra CSS classes |
555
+
556
+ [row gap="4"]
557
+ [col]**Left**[/col]
558
+ [col]**Right**[/col]
559
+ [/row]
560
+
561
+ ---
562
+
563
+ ## [\`col\`]
564
+
565
+ A column inside \`[grid]\` or \`[row]\`. Content is rendered as Markdown.
566
+
567
+ | Attribute | Required | Description |
568
+ |-----------|----------|-------------|
569
+ | \`span\` | No | Columns to span (values must sum to grid \`cols\`) |
570
+ | \`class\` | No | Extra CSS classes |
571
+
572
+ [grid cols="12" gap="4"]
573
+ [col span="8"]**span="8"** — main content[/col]
574
+ [col span="4"]**span="4"** — sidebar[/col]
575
+ [/grid]
576
+
577
+ ---
578
+
579
+ ## [\`card\`]
580
+
581
+ Wraps content in a styled card.
582
+
583
+ | Attribute | Required | Description |
584
+ |-----------|----------|-------------|
585
+ | \`title\` | No | Card header text |
586
+ | \`collapsible\` | No | \`"true"\` to toggle body on header click |
587
+ | \`class\` | No | Extra CSS classes |
588
+
589
+ [card title="Example card"]
590
+ Markdown **works** inside cards, including _italic_, \`code\`, and shortcodes.
591
+ [/card]
592
+
593
+ [card title="Collapsible" collapsible="true"]
594
+ This body starts collapsed.
595
+ [/card]
596
+
597
+ ---
598
+
599
+ ## Embedding a Form
600
+
601
+ Paste this HTML anywhere in your Markdown to embed a form:
602
+
603
+ \`\`\`html
604
+ <div data-form="your-form-slug"></div>
605
+ \`\`\`
606
+
607
+ Replace \`your-form-slug\` with the slug from the Form Builder. Example:
608
+
609
+ \`\`\`html
610
+ <div data-form="contact"></div>
611
+ \`\`\`
612
+
613
+ ---
614
+
615
+ ← [Back to Resources](/resources)
616
+ `
617
+ }
618
+ ];
619
+
620
+ // ---------------------------------------------------------------------------
621
+ // Serialise frontmatter + body to .md string
622
+ // Produces the same YAML-frontmatter format gray-matter reads.
623
+ // ---------------------------------------------------------------------------
624
+
625
+ function toMarkdown(fm, body) {
626
+ const lines = [];
627
+ for (const [k, v] of Object.entries(fm)) {
628
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
629
+ lines.push(`${k}:`);
630
+ for (const [nk, nv] of Object.entries(v)) {
631
+ lines.push(` ${nk}: ${JSON.stringify(nv)}`);
632
+ }
633
+ } else {
634
+ lines.push(`${k}: ${JSON.stringify(v)}`);
635
+ }
636
+ }
637
+ return `---\n${lines.join('\n')}\n---\n\n${body}`;
638
+ }
639
+
640
+ // ---------------------------------------------------------------------------
641
+ // Main
642
+ // ---------------------------------------------------------------------------
643
+
644
+ console.log('');
645
+ console.log(' ┌──────────────────────────────────┐');
646
+ console.log(' │ Domma CMS — Seed Demo Content │');
647
+ console.log(' └──────────────────────────────────┘');
648
+ console.log('');
649
+
650
+ for (const page of PAGES) {
651
+ const filePath = path.join(PAGES_DIR, page.file);
652
+ await mkdir(path.dirname(filePath), { recursive: true });
653
+ await writeFile(filePath, toMarkdown(page.fm, page.body), 'utf8');
654
+ const urlLabel = '/' + page.file.replace(/\\/g, '/').replace(/index\.md$/, '').replace(/\.md$/, '');
655
+ console.log(` ✓ ${urlLabel || '/'}`);
656
+ }
657
+
658
+ process.stdout.write(' Updating navigation…');
659
+ await writeFile(NAV_CFG, JSON.stringify(SEED_NAV, null, 4) + '\n', 'utf8');
660
+ console.log(' done.');
661
+
662
+ console.log('');
663
+ console.log(` ✓ Seed complete — ${PAGES.length} pages created, navigation updated.`);
664
+ console.log(' Visit your site at http://localhost:3050/');
665
+ console.log(' Resources section available at http://localhost:3050/resources');
666
+ console.log('');