domma-cms 1.6.59 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4344 -0
- package/README.md +1 -1
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/draft-owner.js +1 -0
- package/admin/js/lib/effect-defs.js +1 -1
- package/admin/js/lib/effects-builder.js +2 -2
- package/admin/js/lib/page-editor-reference.js +5 -5
- package/admin/js/lib/shortcode-tags.js +1 -1
- package/admin/js/templates/docs/usage-shortcodes.html +39 -0
- package/admin/js/views/user-editor.js +1 -1
- package/docs/DommaFeatures.md +3005 -0
- package/docs/MultiTenant.md +176 -0
- package/docs/api-reference.md +1667 -0
- package/docs/cache.md +96 -0
- package/docs/configuration.md +1811 -0
- package/docs/editions-and-licences.md +190 -0
- package/docs/getting-started.md +201 -0
- package/docs/guides/form-triggers.md +260 -0
- package/docs/guides/mongodb-storage-adapter.md +282 -0
- package/docs/guides/multi-page-forms.md +121 -0
- package/docs/images/scribe-composer.png +0 -0
- package/docs/markdown-shortcodes.md +1738 -0
- package/docs/pentest-report-2026-04-03.md +181 -0
- package/docs/plans/2026-02-28-admin-topbar-login-forms.md +349 -0
- package/docs/plans/2026-02-28-domma-ui-polish.md +286 -0
- package/docs/plans/2026-02-28-reset-seed-fresh-commands.md +520 -0
- package/docs/plans/2026-03-02-cookie-consent-design.md +86 -0
- package/docs/plans/2026-03-02-cookie-consent-plugin.md +453 -0
- package/docs/plans/2026-03-02-tooltip-sweep-and-back-to-top-plugin-design.md +126 -0
- package/docs/plans/2026-03-02-tooltip-sweep-back-to-top.md +427 -0
- package/docs/plans/2026-03-05-cookie-consent-btt-core.md +115 -0
- package/docs/plans/2026-03-05-custom-css-migrate-to-core-design.md +35 -0
- package/docs/plans/2026-03-05-custom-css-migrate-to-core.md +352 -0
- package/docs/plans/2026-03-05-scribe-script-shortcode.md +373 -0
- package/docs/plans/2026-03-05-user-types-design.md +139 -0
- package/docs/plans/2026-03-05-user-types-implementation.md +1035 -0
- package/docs/plans/2026-03-09-page-editor-view-cta-inserts-design.md +78 -0
- package/docs/plans/2026-03-09-page-editor-view-cta-inserts.md +388 -0
- package/docs/plans/2026-03-09-pro-documentation-design.md +80 -0
- package/docs/plans/2026-03-09-pro-documentation.md +1017 -0
- package/docs/plans/2026-06-10-core-project-design.md +240 -0
- package/docs/plugin-development.md +827 -0
- package/docs/recruitment-recipe.md +501 -0
- package/docs/scaffolding.md +312 -0
- package/docs/screenshots/calculator-floating.png +0 -0
- package/docs/screenshots/calculator-standard.png +0 -0
- package/docs/screenshots/email-settings.png +0 -0
- package/docs/screenshots/messages-count.png +0 -0
- package/docs/structure/user-types.md +107 -0
- package/docs/superpowers/plans/2026-05-25-admin-sidebar-via-menus.md +1112 -0
- package/docs/superpowers/plans/2026-06-08-navbar-mobile-drawer-and-menu-enrichment.md +1161 -0
- package/docs/superpowers/plans/2026-06-25-domma-docs-project.md +695 -0
- package/docs/superpowers/plans/2026-06-26-surveys-HANDOFF.md +68 -0
- package/docs/superpowers/plans/2026-06-26-surveys-pro-plugin.md +1902 -0
- package/docs/superpowers/plans/2026-08-19-collection-context-sort-export.md +1577 -0
- package/docs/superpowers/plans/2026-10-09-content-api.md +1192 -0
- package/docs/superpowers/specs/2026-03-12-form-followup-actions-design.md +152 -0
- package/docs/superpowers/specs/2026-03-12-page-editor-form-insert-and-per-page-theme-design.md +115 -0
- package/docs/superpowers/specs/2026-03-17-nav-hidden-items-design.md +85 -0
- package/docs/superpowers/specs/2026-03-19-accordion-insert-design.md +175 -0
- package/docs/superpowers/specs/2026-03-25-static-block-shortcode-design.md +153 -0
- package/docs/superpowers/specs/2026-03-25-text-shortcode-design.md +168 -0
- package/docs/superpowers/specs/2026-04-05-card-builder-design.md +315 -0
- package/docs/superpowers/specs/2026-04-06-insert-builders-design.md +278 -0
- package/docs/superpowers/specs/2026-04-06-layouts-design.md +226 -0
- package/docs/superpowers/specs/2026-04-07-blog-plugin-design.md +300 -0
- package/docs/superpowers/specs/2026-04-07-calendar-plugin-design.md +538 -0
- package/docs/superpowers/specs/2026-04-17-components-area-design.md +368 -0
- package/docs/superpowers/specs/2026-05-02-effects-slideover-overhaul-design.md +193 -0
- package/docs/superpowers/specs/2026-05-06-dashboard-rebuild-design.md +257 -0
- package/docs/superpowers/specs/2026-05-24-menus-design.md +466 -0
- package/docs/superpowers/specs/2026-05-25-admin-sidebar-via-menus-design.md +358 -0
- package/docs/superpowers/specs/2026-05-25-projects-design.md +380 -0
- package/docs/superpowers/specs/2026-06-08-navbar-mobile-drawer-and-menu-enrichment-design.md +292 -0
- package/docs/superpowers/specs/2026-06-08-sidebar-tools-plugins-folders-design.md +59 -0
- package/docs/superpowers/specs/2026-06-25-domma-docs-project-design.md +192 -0
- package/docs/superpowers/specs/2026-06-26-domma-charts-upstream-proposal.md +44 -0
- package/docs/superpowers/specs/2026-06-26-manager-scheduler-upstream-proposal.md +46 -0
- package/docs/superpowers/specs/2026-06-26-surveys-pro-plugin-design.md +206 -0
- package/docs/superpowers/specs/2026-07-02-shortcode-context-menu-design.md +96 -0
- package/docs/superpowers/specs/2026-08-19-collection-context-sort-export-design.md +330 -0
- package/docs/superpowers/specs/2026-09-22-dcms-marketplace-design.md +1150 -0
- package/docs/superpowers/specs/2026-10-09-content-api-design.md +325 -0
- package/docs/superpowers/specs/plans/2026-03-12-form-followup-actions.md +624 -0
- package/docs/superpowers/specs/plans/2026-03-12-page-editor-form-insert-and-per-page-theme.md +125 -0
- package/docs/superpowers/specs/plans/2026-03-17-nav-hidden-items.md +578 -0
- package/docs/superpowers/specs/plans/2026-03-19-accordion-insert.md +635 -0
- package/docs/superpowers/specs/plans/2026-03-25-text-shortcode.md +545 -0
- package/docs/superpowers/specs/plans/2026-04-05-card-builder.md +1970 -0
- package/docs/superpowers/specs/plans/2026-04-06-insert-builders.md +1049 -0
- package/docs/superpowers/specs/plans/2026-04-06-layouts.md +1015 -0
- package/docs/superpowers/specs/plans/2026-04-07-calendar-plugin.md +1526 -0
- package/docs/superpowers/specs/plans/2026-04-08-plugin-monetisation-split.md +242 -0
- package/docs/superpowers/specs/plans/2026-04-17-components-area.md +2038 -0
- package/docs/superpowers/specs/plans/2026-05-02-effects-slideover-overhaul.md +2335 -0
- package/docs/superpowers/specs/plans/2026-05-06-dashboard-rebuild.md +1999 -0
- package/docs/superpowers/specs/plans/2026-05-17-cache-system.md +1436 -0
- package/docs/superpowers/specs/plans/2026-05-24-menus.md +3096 -0
- package/docs/superpowers/specs/plans/2026-05-25-projects.md +2869 -0
- package/docs/superpowers/specs/plans/2026-09-22-marketplace-step2-consolidation.md +505 -0
- package/docs/superpowers/specs/plans/2026-09-22-marketplace-step3-catalogue-and-key.md +154 -0
- package/docs/superpowers/specs/plans/2026-09-22-tools-promotion.md +260 -0
- package/docs/theming.md +320 -0
- package/package.json +2 -2
- package/plugins/_lib/admin/mail/keyboard.js +49 -0
- package/plugins/_lib/admin/mail/reader-view.js +4 -2
- package/public/js/celebrations/core/canvas.js +1 -1
- package/public/js/celebrations/index.js +1 -1
- package/public/js/celebrations/licenses/ABeeZee-Regular-OFL.txt +93 -0
- package/public/js/celebrations/licenses/Allura-Regular-OFL.txt +93 -0
- package/public/js/celebrations/message-attrs.mjs +1 -0
- package/public/js/celebrations/themes/anniversary.js +1 -0
- package/public/js/celebrations/themes/autumn.js +1 -0
- package/public/js/celebrations/themes/birthday.js +1 -0
- package/public/js/celebrations/themes/butterfly-flight.js +1 -0
- package/public/js/celebrations/themes/calendar.js +1 -0
- package/public/js/celebrations/themes/chinese-new-year-dates.js +1 -0
- package/public/js/celebrations/themes/chinese-new-year.js +1 -0
- package/public/js/celebrations/themes/christmas.js +1 -1
- package/public/js/celebrations/themes/easter.js +1 -0
- package/public/js/celebrations/themes/garden-drawing.js +1 -0
- package/public/js/celebrations/themes/garden.js +1 -0
- package/public/js/celebrations/themes/graduation.js +1 -0
- package/public/js/celebrations/themes/greeting.js +1 -0
- package/public/js/celebrations/themes/make-it-rain.js +1 -0
- package/public/js/celebrations/themes/money-rain.js +1 -0
- package/public/js/celebrations/themes/new-year.js +1 -0
- package/public/js/celebrations/themes/occasion-drawing.js +1 -0
- package/public/js/celebrations/themes/occasions.js +1 -0
- package/public/js/celebrations/themes/rain-control.js +1 -0
- package/public/js/celebrations/themes/sparkler-font-data.js +1 -0
- package/public/js/celebrations/themes/sparkler-font.js +1 -0
- package/public/js/celebrations/themes/sparkler-writing.js +1 -0
- package/public/js/celebrations/themes/summer-garden.js +1 -0
- package/public/js/celebrations/themes/winter.js +1 -0
- package/public/js/celebrations/trait-data.mjs +1 -1
- package/public/js/effects.js +1 -1
- package/scripts/build.js +4 -0
- package/server/services/markdown.js +5 -2
- package/server/templates/page.html +1 -1
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
# Reset, Seed & Fresh Commands - Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Add three npm scripts - `npm run reset` (full factory reset), `npm run seed` (demo content), and `npm run fresh` (reset → setup → seed in one go) - that let an end user get a working CMS in under two minutes.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Three standalone ESM scripts in `scripts/`. Each operates directly on files (no server imports). `fresh.js` chains the other three scripts using `node:child_process` `spawnSync` with `stdio: 'inherit'` so all interactive prompts work through. `seed.js` writes markdown files directly as template strings (no gray-matter dependency needed - format is straightforward YAML frontmatter + markdown body).
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** `node:fs/promises`, `node:readline/promises`, `node:child_process`, `node:path` - zero new dependencies.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: `scripts/reset.js` - Full Factory Reset
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Create: `scripts/reset.js`
|
|
17
|
+
- Modify: `package.json`
|
|
18
|
+
|
|
19
|
+
Wipes all user-created data and resets config to factory defaults. Requires typing `yes` to confirm - protects against accidental runs.
|
|
20
|
+
|
|
21
|
+
**What it deletes/resets:**
|
|
22
|
+
- `content/users/*.json` - all user accounts
|
|
23
|
+
- `content/pages/**/*.md` - all pages (recursive)
|
|
24
|
+
- `content/media/*` - all uploaded files
|
|
25
|
+
- `config/site.json` - reset to defaults
|
|
26
|
+
- `config/navigation.json` - reset to defaults
|
|
27
|
+
- `.env` - JWT_SECRET reset to placeholder (so `npm run setup` will regenerate it)
|
|
28
|
+
|
|
29
|
+
**Step 1: Create `scripts/reset.js`**
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
#!/usr/bin/env node
|
|
33
|
+
/**
|
|
34
|
+
* Domma CMS - Factory Reset
|
|
35
|
+
* Wipes all content, users, and resets config to defaults.
|
|
36
|
+
* Run: npm run reset
|
|
37
|
+
*/
|
|
38
|
+
import { createInterface } from 'node:readline/promises';
|
|
39
|
+
import { readFile, writeFile, readdir, rm, mkdir } from 'node:fs/promises';
|
|
40
|
+
import { existsSync } from 'node:fs';
|
|
41
|
+
import path from 'node:path';
|
|
42
|
+
import { fileURLToPath } from 'node:url';
|
|
43
|
+
|
|
44
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
45
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
46
|
+
|
|
47
|
+
const USERS_DIR = path.join(ROOT, 'content', 'users');
|
|
48
|
+
const PAGES_DIR = path.join(ROOT, 'content', 'pages');
|
|
49
|
+
const MEDIA_DIR = path.join(ROOT, 'content', 'media');
|
|
50
|
+
const SITE_CFG = path.join(ROOT, 'config', 'site.json');
|
|
51
|
+
const NAV_CFG = path.join(ROOT, 'config', 'navigation.json');
|
|
52
|
+
const ENV_FILE = path.join(ROOT, '.env');
|
|
53
|
+
|
|
54
|
+
const DEFAULT_SITE = {
|
|
55
|
+
title: 'My Site',
|
|
56
|
+
tagline: 'Powered by Domma CMS',
|
|
57
|
+
theme: 'charcoal-dark',
|
|
58
|
+
seo: {
|
|
59
|
+
defaultTitle: 'My Site',
|
|
60
|
+
titleSeparator: ' | ',
|
|
61
|
+
defaultDescription: 'A site built with Domma CMS'
|
|
62
|
+
},
|
|
63
|
+
footer: {
|
|
64
|
+
copyright: `© ${new Date().getFullYear()} My Site. All rights reserved.`,
|
|
65
|
+
links: [
|
|
66
|
+
{ text: 'Privacy Policy', url: '/privacy' },
|
|
67
|
+
{ text: 'Contact', url: '/contact' }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const DEFAULT_NAV = {
|
|
73
|
+
brand: { text: 'My Site', logo: null, url: '/' },
|
|
74
|
+
items: [
|
|
75
|
+
{ text: 'Home', url: '/', icon: 'home' },
|
|
76
|
+
{ text: 'About', url: '/about', icon: 'info' },
|
|
77
|
+
{ text: 'Contact', url: '/contact', icon: 'mail' }
|
|
78
|
+
],
|
|
79
|
+
variant: 'dark',
|
|
80
|
+
position: 'sticky'
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
async function deleteDir(dir) {
|
|
86
|
+
try {
|
|
87
|
+
await rm(dir, { recursive: true, force: true });
|
|
88
|
+
await mkdir(dir, { recursive: true });
|
|
89
|
+
} catch { /* dir may not exist */ }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function resetEnv() {
|
|
93
|
+
if (!existsSync(ENV_FILE)) return;
|
|
94
|
+
const lines = (await readFile(ENV_FILE, 'utf8')).split('\n');
|
|
95
|
+
const updated = lines.map(l => {
|
|
96
|
+
if (l.startsWith('JWT_SECRET=')) {
|
|
97
|
+
return 'JWT_SECRET=change-me-to-a-64-char-random-string-before-deploying-to-production';
|
|
98
|
+
}
|
|
99
|
+
return l;
|
|
100
|
+
});
|
|
101
|
+
await writeFile(ENV_FILE, updated.join('\n'), 'utf8');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log(' ┌──────────────────────────────────┐');
|
|
108
|
+
console.log(' │ Domma CMS - Factory Reset │');
|
|
109
|
+
console.log(' └──────────────────────────────────┘');
|
|
110
|
+
console.log('');
|
|
111
|
+
console.log(' This will permanently delete:');
|
|
112
|
+
console.log(' • All user accounts (content/users/)');
|
|
113
|
+
console.log(' • All pages (content/pages/)');
|
|
114
|
+
console.log(' • All media uploads (content/media/)');
|
|
115
|
+
console.log(' • config/site.json and config/navigation.json');
|
|
116
|
+
console.log(' • JWT_SECRET in .env');
|
|
117
|
+
console.log('');
|
|
118
|
+
|
|
119
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
120
|
+
const answer = (await rl.question(' Type "yes" to confirm: ')).trim();
|
|
121
|
+
rl.close();
|
|
122
|
+
|
|
123
|
+
if (answer !== 'yes') {
|
|
124
|
+
console.log('\n Reset cancelled.\n');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log('');
|
|
129
|
+
process.stdout.write(' Deleting users…');
|
|
130
|
+
await deleteDir(USERS_DIR);
|
|
131
|
+
console.log(' done.');
|
|
132
|
+
|
|
133
|
+
process.stdout.write(' Deleting pages…');
|
|
134
|
+
await deleteDir(PAGES_DIR);
|
|
135
|
+
console.log(' done.');
|
|
136
|
+
|
|
137
|
+
process.stdout.write(' Deleting media…');
|
|
138
|
+
await deleteDir(MEDIA_DIR);
|
|
139
|
+
console.log(' done.');
|
|
140
|
+
|
|
141
|
+
process.stdout.write(' Resetting config/site.json…');
|
|
142
|
+
await writeFile(SITE_CFG, JSON.stringify(DEFAULT_SITE, null, 4) + '\n', 'utf8');
|
|
143
|
+
console.log(' done.');
|
|
144
|
+
|
|
145
|
+
process.stdout.write(' Resetting config/navigation.json…');
|
|
146
|
+
await writeFile(NAV_CFG, JSON.stringify(DEFAULT_NAV, null, 4) + '\n', 'utf8');
|
|
147
|
+
console.log(' done.');
|
|
148
|
+
|
|
149
|
+
process.stdout.write(' Resetting JWT_SECRET in .env…');
|
|
150
|
+
await resetEnv();
|
|
151
|
+
console.log(' done.');
|
|
152
|
+
|
|
153
|
+
console.log('');
|
|
154
|
+
console.log(' ✓ Factory reset complete.');
|
|
155
|
+
console.log(' Run `npm run setup` to configure a new admin account.');
|
|
156
|
+
console.log('');
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Step 2: Add to `package.json` scripts**
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
"reset": "node scripts/reset.js"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Step 3: Verify**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
node --check scripts/reset.js
|
|
169
|
+
```
|
|
170
|
+
Expected: no output (syntax OK).
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Task 2: `scripts/seed.js` - Demo Content
|
|
175
|
+
|
|
176
|
+
**Files:**
|
|
177
|
+
- Create: `scripts/seed.js`
|
|
178
|
+
- Modify: `package.json`
|
|
179
|
+
|
|
180
|
+
Writes five sample pages and updates navigation. Safe to run on a fresh install or alongside existing content (overwrites pages at the same paths). Does **not** touch users or `.env`.
|
|
181
|
+
|
|
182
|
+
**Pages created:**
|
|
183
|
+
| URL | File |
|
|
184
|
+
|-----|------|
|
|
185
|
+
| `/` | `content/pages/index.md` |
|
|
186
|
+
| `/about` | `content/pages/about.md` |
|
|
187
|
+
| `/contact` | `content/pages/contact.md` |
|
|
188
|
+
| `/blog` | `content/pages/blog/index.md` |
|
|
189
|
+
| `/blog/hello-world` | `content/pages/blog/hello-world.md` |
|
|
190
|
+
|
|
191
|
+
**Step 1: Create `scripts/seed.js`**
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
#!/usr/bin/env node
|
|
195
|
+
/**
|
|
196
|
+
* Domma CMS - Seed Demo Content
|
|
197
|
+
* Creates sample pages and updates navigation.
|
|
198
|
+
* Safe to run multiple times - overwrites seed paths only.
|
|
199
|
+
* Run: npm run seed
|
|
200
|
+
*/
|
|
201
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
202
|
+
import path from 'node:path';
|
|
203
|
+
import { fileURLToPath } from 'node:url';
|
|
204
|
+
|
|
205
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
206
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
207
|
+
|
|
208
|
+
const PAGES_DIR = path.join(ROOT, 'content', 'pages');
|
|
209
|
+
const NAV_CFG = path.join(ROOT, 'config', 'navigation.json');
|
|
210
|
+
|
|
211
|
+
const now = new Date().toISOString();
|
|
212
|
+
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Page definitions
|
|
215
|
+
// ---------------------------------------------------------------------------
|
|
216
|
+
|
|
217
|
+
const pages = [
|
|
218
|
+
{
|
|
219
|
+
file: 'index.md',
|
|
220
|
+
frontmatter: {
|
|
221
|
+
title: 'Welcome', slug: 'index',
|
|
222
|
+
description: 'Your new website, powered by Domma CMS',
|
|
223
|
+
layout: 'default', status: 'published',
|
|
224
|
+
sortOrder: 1, showInNav: false, sidebar: false,
|
|
225
|
+
seo: { title: 'Welcome', description: 'Your new website, powered by Domma CMS' },
|
|
226
|
+
createdAt: now, updatedAt: now
|
|
227
|
+
},
|
|
228
|
+
body: `# Welcome
|
|
229
|
+
|
|
230
|
+
This is your new website, powered by **Domma CMS**.
|
|
231
|
+
|
|
232
|
+
Edit this page from the [admin panel](/admin/), or modify \`content/pages/index.md\` directly.
|
|
233
|
+
|
|
234
|
+
## What you can do
|
|
235
|
+
|
|
236
|
+
- **Write pages** - create and publish content in Markdown
|
|
237
|
+
- **Manage navigation** - build your site's menu from the admin panel
|
|
238
|
+
- **Upload media** - attach images and files to your pages
|
|
239
|
+
- **Choose a theme** - pick from 16 built-in colour schemes
|
|
240
|
+
|
|
241
|
+
[Sign in to the admin panel →](/admin/)
|
|
242
|
+
`
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
file: 'about.md',
|
|
246
|
+
frontmatter: {
|
|
247
|
+
title: 'About', slug: 'about',
|
|
248
|
+
description: 'Learn more about us',
|
|
249
|
+
layout: 'default', status: 'published',
|
|
250
|
+
sortOrder: 2, showInNav: true, sidebar: false,
|
|
251
|
+
seo: { title: 'About', description: 'Learn more about us' },
|
|
252
|
+
createdAt: now, updatedAt: now
|
|
253
|
+
},
|
|
254
|
+
body: `# About
|
|
255
|
+
|
|
256
|
+
This is the About page - tell your visitors who you are, what you do, and why it matters.
|
|
257
|
+
|
|
258
|
+
## Our story
|
|
259
|
+
|
|
260
|
+
Replace this content with your own. You can edit it from the [admin panel](/admin/) at any time.
|
|
261
|
+
|
|
262
|
+
## What we do
|
|
263
|
+
|
|
264
|
+
Add your services, mission statement, or team information here.
|
|
265
|
+
`
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
file: 'contact.md',
|
|
269
|
+
frontmatter: {
|
|
270
|
+
title: 'Contact', slug: 'contact',
|
|
271
|
+
description: 'Get in touch',
|
|
272
|
+
layout: 'default', status: 'published',
|
|
273
|
+
sortOrder: 4, showInNav: true, sidebar: false,
|
|
274
|
+
seo: { title: 'Contact', description: 'Get in touch with us' },
|
|
275
|
+
createdAt: now, updatedAt: now
|
|
276
|
+
},
|
|
277
|
+
body: `# Contact
|
|
278
|
+
|
|
279
|
+
Get in touch - we'd love to hear from you.
|
|
280
|
+
|
|
281
|
+
## How to reach us
|
|
282
|
+
|
|
283
|
+
Replace this with your own contact details, a contact form, or whatever works best for your site.
|
|
284
|
+
|
|
285
|
+
You can edit this page from the [admin panel](/admin/).
|
|
286
|
+
`
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
file: path.join('blog', 'index.md'),
|
|
290
|
+
frontmatter: {
|
|
291
|
+
title: 'Blog', slug: 'blog',
|
|
292
|
+
description: 'News, updates and articles',
|
|
293
|
+
layout: 'default', status: 'published',
|
|
294
|
+
sortOrder: 3, showInNav: true, sidebar: false,
|
|
295
|
+
seo: { title: 'Blog', description: 'News, updates and articles' },
|
|
296
|
+
createdAt: now, updatedAt: now
|
|
297
|
+
},
|
|
298
|
+
body: `# Blog
|
|
299
|
+
|
|
300
|
+
Welcome to the blog. Read on for articles, updates and news.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
- [Hello, World!](/blog/hello-world) - Your first post
|
|
305
|
+
`
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
file: path.join('blog', 'hello-world.md'),
|
|
309
|
+
frontmatter: {
|
|
310
|
+
title: 'Hello, World!', slug: 'hello-world',
|
|
311
|
+
description: 'The first post on this site',
|
|
312
|
+
layout: 'default', status: 'published',
|
|
313
|
+
sortOrder: 1, showInNav: false, sidebar: false,
|
|
314
|
+
seo: { title: 'Hello, World!', description: 'The first post on this site' },
|
|
315
|
+
createdAt: now, updatedAt: now
|
|
316
|
+
},
|
|
317
|
+
body: `# Hello, World!
|
|
318
|
+
|
|
319
|
+
Welcome to your first blog post, created by the Domma CMS seed script.
|
|
320
|
+
|
|
321
|
+
Edit or delete this from the [admin panel](/admin/), then start writing your own content.
|
|
322
|
+
|
|
323
|
+
## Writing in Markdown
|
|
324
|
+
|
|
325
|
+
Domma CMS uses **Markdown** for all page content:
|
|
326
|
+
|
|
327
|
+
- **Bold** with \`**double asterisks**\`
|
|
328
|
+
- *Italic* with \`*single asterisks*\`
|
|
329
|
+
- \`Inline code\` with backticks
|
|
330
|
+
- [Links](https://example.com) with \`[text](url)\`
|
|
331
|
+
|
|
332
|
+
> Blockquotes with \`>\`
|
|
333
|
+
|
|
334
|
+
\`\`\`
|
|
335
|
+
Code blocks with triple backticks
|
|
336
|
+
\`\`\`
|
|
337
|
+
|
|
338
|
+
Happy writing!
|
|
339
|
+
`
|
|
340
|
+
}
|
|
341
|
+
];
|
|
342
|
+
|
|
343
|
+
// ---------------------------------------------------------------------------
|
|
344
|
+
// Seed navigation
|
|
345
|
+
// ---------------------------------------------------------------------------
|
|
346
|
+
|
|
347
|
+
const seedNav = {
|
|
348
|
+
brand: { text: 'My Site', logo: null, url: '/' },
|
|
349
|
+
items: [
|
|
350
|
+
{ text: 'Home', url: '/', icon: 'home' },
|
|
351
|
+
{ text: 'About', url: '/about', icon: 'info' },
|
|
352
|
+
{ text: 'Blog', url: '/blog', icon: 'book-open' },
|
|
353
|
+
{ text: 'Contact', url: '/contact', icon: 'mail' }
|
|
354
|
+
],
|
|
355
|
+
variant: 'dark',
|
|
356
|
+
position: 'sticky'
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// ---------------------------------------------------------------------------
|
|
360
|
+
// Helpers
|
|
361
|
+
// ---------------------------------------------------------------------------
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Serialise frontmatter + body to a markdown file string.
|
|
365
|
+
* Uses the same YAML-frontmatter format gray-matter produces.
|
|
366
|
+
*
|
|
367
|
+
* @param {object} fm
|
|
368
|
+
* @param {string} body
|
|
369
|
+
* @returns {string}
|
|
370
|
+
*/
|
|
371
|
+
function toMarkdown(fm, body) {
|
|
372
|
+
const yaml = Object.entries(fm).map(([k, v]) => {
|
|
373
|
+
if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
|
|
374
|
+
const nested = Object.entries(v)
|
|
375
|
+
.map(([nk, nv]) => ` ${nk}: ${JSON.stringify(nv)}`)
|
|
376
|
+
.join('\n');
|
|
377
|
+
return `${k}:\n${nested}`;
|
|
378
|
+
}
|
|
379
|
+
return `${k}: ${JSON.stringify(v)}`;
|
|
380
|
+
}).join('\n');
|
|
381
|
+
return `---\n${yaml}\n---\n\n${body}`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// Main
|
|
386
|
+
// ---------------------------------------------------------------------------
|
|
387
|
+
|
|
388
|
+
console.log('');
|
|
389
|
+
console.log(' ┌──────────────────────────────────┐');
|
|
390
|
+
console.log(' │ Domma CMS - Seed Demo Content │');
|
|
391
|
+
console.log(' └──────────────────────────────────┘');
|
|
392
|
+
console.log('');
|
|
393
|
+
|
|
394
|
+
for (const page of pages) {
|
|
395
|
+
const filePath = path.join(PAGES_DIR, page.file);
|
|
396
|
+
await mkdir(path.dirname(filePath), { recursive: true });
|
|
397
|
+
await writeFile(filePath, toMarkdown(page.frontmatter, page.body), 'utf8');
|
|
398
|
+
console.log(` ✓ Created /${page.file.replace(/\\/g, '/').replace('index.md', '').replace('.md', '') || ''}`);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
process.stdout.write(' Updating navigation…');
|
|
402
|
+
await writeFile(NAV_CFG, JSON.stringify(seedNav, null, 4) + '\n', 'utf8');
|
|
403
|
+
console.log(' done.');
|
|
404
|
+
|
|
405
|
+
console.log('');
|
|
406
|
+
console.log(' ✓ Seed complete - 5 pages created, navigation updated.');
|
|
407
|
+
console.log(' Visit your site at http://localhost:4096/');
|
|
408
|
+
console.log('');
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Step 2: Add to `package.json` scripts**
|
|
412
|
+
|
|
413
|
+
```json
|
|
414
|
+
"seed": "node scripts/seed.js"
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
**Step 3: Verify**
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
node --check scripts/seed.js
|
|
421
|
+
```
|
|
422
|
+
Expected: no output (syntax OK).
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
### Task 3: `scripts/fresh.js` - Reset → Setup → Seed
|
|
427
|
+
|
|
428
|
+
**Files:**
|
|
429
|
+
- Create: `scripts/fresh.js`
|
|
430
|
+
- Modify: `package.json`
|
|
431
|
+
|
|
432
|
+
Chains all three scripts in order with full stdio inheritance so interactive prompts (reset confirmation, setup questions) pass through directly to the terminal. Each sub-script runs in the same working directory with `cwd: ROOT`.
|
|
433
|
+
|
|
434
|
+
**Step 1: Create `scripts/fresh.js`**
|
|
435
|
+
|
|
436
|
+
```javascript
|
|
437
|
+
#!/usr/bin/env node
|
|
438
|
+
/**
|
|
439
|
+
* Domma CMS - Fresh Install
|
|
440
|
+
* Chains: reset → setup → seed
|
|
441
|
+
* Gives you a fully configured CMS with demo content in one command.
|
|
442
|
+
* Run: npm run fresh
|
|
443
|
+
*/
|
|
444
|
+
import { spawnSync } from 'node:child_process';
|
|
445
|
+
import path from 'node:path';
|
|
446
|
+
import { fileURLToPath } from 'node:url';
|
|
447
|
+
|
|
448
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
449
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
450
|
+
|
|
451
|
+
function run(script) {
|
|
452
|
+
const result = spawnSync(process.execPath, [path.join('scripts', script)], {
|
|
453
|
+
cwd: ROOT,
|
|
454
|
+
stdio: 'inherit'
|
|
455
|
+
});
|
|
456
|
+
if (result.status !== 0) {
|
|
457
|
+
process.exit(result.status ?? 1);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
console.log('');
|
|
462
|
+
console.log(' ╔══════════════════════════════════════╗');
|
|
463
|
+
console.log(' ║ Domma CMS - Fresh Install ║');
|
|
464
|
+
console.log(' ║ reset → setup → seed ║');
|
|
465
|
+
console.log(' ╚══════════════════════════════════════╝');
|
|
466
|
+
|
|
467
|
+
run('reset.js');
|
|
468
|
+
run('setup.js');
|
|
469
|
+
run('seed.js');
|
|
470
|
+
|
|
471
|
+
console.log('');
|
|
472
|
+
console.log(' ═══════════════════════════════════════════');
|
|
473
|
+
console.log(' Fresh install complete! Start the server:');
|
|
474
|
+
console.log(' npm start');
|
|
475
|
+
console.log(' ═══════════════════════════════════════════');
|
|
476
|
+
console.log('');
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
**Step 2: Add to `package.json` scripts**
|
|
480
|
+
|
|
481
|
+
```json
|
|
482
|
+
"fresh": "node scripts/fresh.js"
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**Step 3: Verify all three scripts**
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
node --check scripts/reset.js && node --check scripts/seed.js && node --check scripts/fresh.js && echo "ALL OK"
|
|
489
|
+
```
|
|
490
|
+
Expected: `ALL OK`
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
### Task 4: Final `package.json` - confirm all four scripts together
|
|
495
|
+
|
|
496
|
+
The scripts block should read:
|
|
497
|
+
|
|
498
|
+
```json
|
|
499
|
+
"scripts": {
|
|
500
|
+
"start": "node server/server.js",
|
|
501
|
+
"dev": "node --watch server/server.js",
|
|
502
|
+
"setup": "node scripts/setup.js",
|
|
503
|
+
"reset": "node scripts/reset.js",
|
|
504
|
+
"seed": "node scripts/seed.js",
|
|
505
|
+
"fresh": "node scripts/fresh.js",
|
|
506
|
+
"copy-domma": "node scripts/copy-domma.js"
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
### Verification Checklist
|
|
513
|
+
|
|
514
|
+
1. `node --check scripts/reset.js` → no errors
|
|
515
|
+
2. `node --check scripts/seed.js` → no errors
|
|
516
|
+
3. `node --check scripts/fresh.js` → no errors
|
|
517
|
+
4. `npm run seed` on a fresh install - creates 5 pages, check `content/pages/`
|
|
518
|
+
5. `npm run reset` - type "yes", verify `content/users/` and `content/pages/` are empty, `config/site.json` is reset
|
|
519
|
+
6. `npm run fresh` - walks through reset → setup → seed, server starts cleanly after
|
|
520
|
+
7. Public site at `http://localhost:4096/` shows Home, About, Blog, Contact in nav
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Cookie Consent Plugin Design
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-03-02
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
A CMS plugin that injects Domma's built-in `Domma.components.cookieConsent()` banner into every public page, with all
|
|
10
|
+
wording, appearance, and category settings configurable from the admin panel.
|
|
11
|
+
|
|
12
|
+
## Decisions
|
|
13
|
+
|
|
14
|
+
- **Banner only** - no script blocking or GTM/GA integration. Stores consent preferences in localStorage via Domma's
|
|
15
|
+
component. Site owner hooks into consent themselves if needed.
|
|
16
|
+
- **All four categories** - Necessary (always required), Functional, Analytics, Marketing. Admin can toggle
|
|
17
|
+
Functional/Analytics/Marketing on or off.
|
|
18
|
+
- **Both layout and position configurable** - `bar` or `modal` layout; `top` or `bottom` position; `light` or `dark`
|
|
19
|
+
theme.
|
|
20
|
+
- **Uses Domma's component directly** - `inject-body.html` calls `Domma.components.cookieConsent(cfg)`. Domma is already
|
|
21
|
+
loaded on public pages via `site.js`, so no extra dependencies.
|
|
22
|
+
|
|
23
|
+
## File Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
plugins/cookie-consent/
|
|
27
|
+
├── plugin.json
|
|
28
|
+
├── plugin.js - GET /settings (public), PUT /settings (admin-auth)
|
|
29
|
+
├── config.js - defaults
|
|
30
|
+
├── admin/
|
|
31
|
+
│ ├── views/cookie-consent-settings.js
|
|
32
|
+
│ └── templates/cookie-consent-settings.html
|
|
33
|
+
└── public/
|
|
34
|
+
└── inject-body.html - IIFE
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Config Defaults
|
|
38
|
+
|
|
39
|
+
| Key | Default | Notes |
|
|
40
|
+
|-----------------------|----------------------|--------------------------------|
|
|
41
|
+
| `message` | `'We use cookies…'` | Main banner text |
|
|
42
|
+
| `acceptAllText` | `'Accept All'` | Accept button label |
|
|
43
|
+
| `rejectAllText` | `'Reject All'` | Reject button label |
|
|
44
|
+
| `customizeText` | `'Customize'` | Customize button label |
|
|
45
|
+
| `savePreferencesText` | `'Save Preferences'` | Save button in customize panel |
|
|
46
|
+
| `privacyPolicyText` | `'Privacy Policy'` | Privacy link label |
|
|
47
|
+
| `privacyPolicyUrl` | `'/privacy-policy'` | Privacy link URL |
|
|
48
|
+
| `cookiePolicyText` | `'Cookie Policy'` | Cookie policy link label |
|
|
49
|
+
| `cookiePolicyUrl` | `''` | Empty = link not shown |
|
|
50
|
+
| `position` | `'bottom'` | `'bottom'` or `'top'` |
|
|
51
|
+
| `layout` | `'bar'` | `'bar'` or `'modal'` |
|
|
52
|
+
| `theme` | `'dark'` | `'light'` or `'dark'` |
|
|
53
|
+
| `showFunctional` | `true` | Show Functional category |
|
|
54
|
+
| `showAnalytics` | `true` | Show Analytics category |
|
|
55
|
+
| `showMarketing` | `true` | Show Marketing category |
|
|
56
|
+
| `consentVersion` | `'1.0'` | Increment to re-prompt users |
|
|
57
|
+
|
|
58
|
+
## Admin Settings Form
|
|
59
|
+
|
|
60
|
+
**Banner Wording card:**
|
|
61
|
+
|
|
62
|
+
- Textarea: Main message
|
|
63
|
+
- Text inputs: Accept All, Reject All, Customize, Save Preferences button labels
|
|
64
|
+
- Text input + URL pairs: Privacy Policy, Cookie Policy (empty URL hides the link)
|
|
65
|
+
|
|
66
|
+
**Appearance & Categories card:**
|
|
67
|
+
|
|
68
|
+
- Select: Position (Bottom / Top)
|
|
69
|
+
- Select: Layout (Bar / Modal)
|
|
70
|
+
- Select: Theme (Dark / Light)
|
|
71
|
+
- Checkboxes: Show Functional, Show Analytics, Show Marketing categories
|
|
72
|
+
- Text input: Consent version
|
|
73
|
+
|
|
74
|
+
## inject-body.html
|
|
75
|
+
|
|
76
|
+
IIFE that:
|
|
77
|
+
|
|
78
|
+
1. Fetches `/api/plugins/cookie-consent/settings` (unauthenticated)
|
|
79
|
+
2. Maps flat config → Domma `categories` object (only includes enabled categories)
|
|
80
|
+
3. Calls `Domma.components.cookieConsent(cfg)`
|
|
81
|
+
4. Catches errors silently (no banner shown if fetch fails)
|
|
82
|
+
|
|
83
|
+
## Note on Public GET Endpoint
|
|
84
|
+
|
|
85
|
+
Same pattern as back-to-top: `GET /settings` is unauthenticated. Returns only display config - no credentials.
|
|
86
|
+
Intentional and safe.
|