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,352 @@
|
|
|
1
|
+
# Custom CSS - Migrate to Core Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
|
4
|
+
|
|
5
|
+
**Goal:** Move the Custom CSS plugin into core, storing CSS at `content/custom.css`, serving it as an inline `<style>` block, and editing it via a new tab in Site Settings.
|
|
6
|
+
|
|
7
|
+
**Architecture:** The CSS file lives at `content/custom.css`. The renderer reads it at request time and injects it as an inline `<style>` block in `headInjectLate`. Two new routes on the settings router handle admin read/write. The admin UI is a new "Custom CSS" tab in settings.html with its own Save button (separate from the main Save, since it writes a file not JSON config). The plugin directory and plugins.json entry are then removed.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** Fastify 5 ESM backend, Domma SPA admin, `fs/promises` for file I/O, `content/custom.css` as storage.
|
|
10
|
+
|
|
11
|
+
**Reference files:** `server/routes/api/settings.js` (lines 1-59), `server/services/renderer.js` (lines 29-86), `admin/js/views/settings.js` (lines 1-117), `admin/js/templates/settings.html` (lines 1-287), `plugins/custom-css/plugin.js`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### Task 1: Create content/custom.css
|
|
16
|
+
|
|
17
|
+
**Files:**
|
|
18
|
+
- Create: `content/custom.css`
|
|
19
|
+
|
|
20
|
+
**Step 1: Create the empty file**
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
touch content/custom.css
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Step 2: Verify it exists**
|
|
27
|
+
|
|
28
|
+
Run: `ls -la content/custom.css`
|
|
29
|
+
|
|
30
|
+
Expected: file listed with 0 bytes.
|
|
31
|
+
|
|
32
|
+
**Step 3: Commit**
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git add content/custom.css
|
|
36
|
+
git commit -m "feat: add content/custom.css for core custom CSS storage"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Task 2: Add custom-css routes to settings.js
|
|
42
|
+
|
|
43
|
+
**Files:**
|
|
44
|
+
- Modify: `server/routes/api/settings.js`
|
|
45
|
+
|
|
46
|
+
**Step 1: Add fs import at the top**
|
|
47
|
+
|
|
48
|
+
After the existing imports (after line 10), add:
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import fs from 'fs/promises';
|
|
52
|
+
import path from 'path';
|
|
53
|
+
import {fileURLToPath} from 'url';
|
|
54
|
+
|
|
55
|
+
const __dirname_settings = path.dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
const CUSTOM_CSS_FILE = path.resolve(__dirname_settings, '../../../content/custom.css');
|
|
57
|
+
const CUSTOM_CSS_MAX = 100 * 1024; // 100 KB
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Step 2: Add the two new routes inside `settingsRoutes`, after the test-email handler**
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
// GET /api/settings/custom-css - return current CSS as JSON
|
|
64
|
+
fastify.get('/settings/custom-css', guard, async () => {
|
|
65
|
+
try {
|
|
66
|
+
const css = await fs.readFile(CUSTOM_CSS_FILE, 'utf8');
|
|
67
|
+
return { css };
|
|
68
|
+
} catch {
|
|
69
|
+
return { css: '' };
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// PUT /api/settings/custom-css - save CSS to content/custom.css
|
|
74
|
+
fastify.put('/settings/custom-css', guard, async (request, reply) => {
|
|
75
|
+
const { css } = request.body || {};
|
|
76
|
+
if (typeof css !== 'string') {
|
|
77
|
+
return reply.status(400).send({ error: 'css must be a string.' });
|
|
78
|
+
}
|
|
79
|
+
if (Buffer.byteLength(css, 'utf8') > CUSTOM_CSS_MAX) {
|
|
80
|
+
return reply.status(400).send({ error: 'CSS exceeds the 100 KB limit.' });
|
|
81
|
+
}
|
|
82
|
+
await fs.writeFile(CUSTOM_CSS_FILE, css, 'utf8');
|
|
83
|
+
return { ok: true };
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Step 3: Verify the file imports without errors**
|
|
88
|
+
|
|
89
|
+
Run: `node --input-type=module --eval "import('/home/darryl/src/js/domma-cms/server/routes/api/settings.js').then(()=>console.log('OK')).catch(e=>{console.error(e.message);process.exit(1);})" 2>&1`
|
|
90
|
+
|
|
91
|
+
Expected: `OK`
|
|
92
|
+
|
|
93
|
+
**Step 4: Commit**
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
git add server/routes/api/settings.js
|
|
97
|
+
git commit -m "feat: add GET/PUT /api/settings/custom-css routes"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Task 3: Update renderer.js to inject inline custom CSS
|
|
103
|
+
|
|
104
|
+
**Files:**
|
|
105
|
+
- Modify: `server/services/renderer.js`
|
|
106
|
+
|
|
107
|
+
**Step 1: Add fs import and CSS_FILE constant**
|
|
108
|
+
|
|
109
|
+
After the existing imports (after line 10 `import {applyTransforms} from './hooks.js';`), add:
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import fs from 'fs/promises';
|
|
113
|
+
|
|
114
|
+
const CUSTOM_CSS_PATH = new URL('../../../content/custom.css', import.meta.url).pathname;
|
|
115
|
+
|
|
116
|
+
async function getCustomCss() {
|
|
117
|
+
try {
|
|
118
|
+
return await fs.readFile(CUSTOM_CSS_PATH, 'utf8');
|
|
119
|
+
} catch {
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Step 2: Add `getCustomCss()` to the Promise.all in renderPage**
|
|
126
|
+
|
|
127
|
+
Current line 30:
|
|
128
|
+
```js
|
|
129
|
+
const [template, site, navigation, presets, injection] = await Promise.all([
|
|
130
|
+
getTemplate(),
|
|
131
|
+
Promise.resolve(getConfig('site')),
|
|
132
|
+
Promise.resolve(getConfig('navigation')),
|
|
133
|
+
Promise.resolve(getConfig('presets')),
|
|
134
|
+
getInjectionSnippets()
|
|
135
|
+
]);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Replace with:
|
|
139
|
+
```js
|
|
140
|
+
const [template, site, navigation, presets, injection, customCss] = await Promise.all([
|
|
141
|
+
getTemplate(),
|
|
142
|
+
Promise.resolve(getConfig('site')),
|
|
143
|
+
Promise.resolve(getConfig('navigation')),
|
|
144
|
+
Promise.resolve(getConfig('presets')),
|
|
145
|
+
getInjectionSnippets(),
|
|
146
|
+
getCustomCss()
|
|
147
|
+
]);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Step 3: Build the customCssTag variable and extend headInjectLate**
|
|
151
|
+
|
|
152
|
+
After the `fontStyleTag` lines (after line 56), add:
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
const customCssTag = customCss.trim()
|
|
156
|
+
? `<style>${customCss.replace(/<\/style>/gi, '<\\/style>')}</style>`
|
|
157
|
+
: '';
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Then in the `vars` object, change `headInjectLate`:
|
|
161
|
+
|
|
162
|
+
Current:
|
|
163
|
+
```js
|
|
164
|
+
headInjectLate: injection.headLate,
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Replace with:
|
|
168
|
+
```js
|
|
169
|
+
headInjectLate: [injection.headLate, customCssTag].filter(Boolean).join('\n'),
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**Step 4: Verify renderer imports without errors**
|
|
173
|
+
|
|
174
|
+
Run: `node --input-type=module --eval "import('/home/darryl/src/js/domma-cms/server/services/renderer.js').then(()=>console.log('OK')).catch(e=>{console.error(e.message);process.exit(1);})" 2>&1`
|
|
175
|
+
|
|
176
|
+
Expected: `OK`
|
|
177
|
+
|
|
178
|
+
**Step 5: Verify inline style tag appears when CSS is non-empty**
|
|
179
|
+
|
|
180
|
+
Write a test string to the file, curl the page, then clear it:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
echo "body { outline: 2px solid red; }" > content/custom.css
|
|
184
|
+
curl -s http://localhost:4096/ | grep -o '<style>body.*</style>'
|
|
185
|
+
echo "" > content/custom.css
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Expected: `<style>body { outline: 2px solid red; }</style>` (or similar match).
|
|
189
|
+
|
|
190
|
+
**Step 6: Commit**
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
git add server/services/renderer.js
|
|
194
|
+
git commit -m "feat: renderer injects content/custom.css as inline style block"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### Task 4: Add Custom CSS tab to settings.html
|
|
200
|
+
|
|
201
|
+
**Files:**
|
|
202
|
+
- Modify: `admin/js/templates/settings.html`
|
|
203
|
+
|
|
204
|
+
**Step 1: Add tab button after the Cookie Consent button**
|
|
205
|
+
|
|
206
|
+
Current last tab button:
|
|
207
|
+
```html
|
|
208
|
+
<button class="tab-item">Cookie Consent</button>
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Add after it:
|
|
212
|
+
```html
|
|
213
|
+
<button class="tab-item">Custom CSS</button>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Step 2: Add the tab panel before the closing `</div></div>`**
|
|
217
|
+
|
|
218
|
+
Add before the final ` </div>\n</div>`:
|
|
219
|
+
|
|
220
|
+
```html
|
|
221
|
+
<!-- Custom CSS -->
|
|
222
|
+
<div class="tab-panel">
|
|
223
|
+
<div class="row mb-3">
|
|
224
|
+
<div class="col">
|
|
225
|
+
<p class="text-muted" style="font-size:.875rem;margin-bottom:1rem;">
|
|
226
|
+
CSS entered here is injected as an inline <code><style></code> block into the
|
|
227
|
+
<code><head></code> of every public page. Changes take effect immediately on save.
|
|
228
|
+
</p>
|
|
229
|
+
<textarea id="field-custom-css" class="form-input" style="font-family:monospace;min-height:420px;resize:vertical;" spellcheck="false" placeholder="/* Add your custom CSS here */"></textarea>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
<div class="row">
|
|
233
|
+
<div class="col">
|
|
234
|
+
<button id="save-css-btn" class="btn btn-primary"><span data-icon="save"></span> Save CSS</button>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Step 3: Commit**
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
git add admin/js/templates/settings.html
|
|
244
|
+
git commit -m "feat: add Custom CSS tab to Site Settings template"
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### Task 5: Update settings.js to load/save custom CSS
|
|
250
|
+
|
|
251
|
+
**Files:**
|
|
252
|
+
- Modify: `admin/js/views/settings.js`
|
|
253
|
+
|
|
254
|
+
**Step 1: Load CSS in onMount, after the Cookie Consent fields**
|
|
255
|
+
|
|
256
|
+
After the last `$container.find('#field-cc-version')...` line, add:
|
|
257
|
+
|
|
258
|
+
```js
|
|
259
|
+
// Custom CSS
|
|
260
|
+
try {
|
|
261
|
+
const { css } = await apiRequest('/settings/custom-css');
|
|
262
|
+
$container.find('#field-custom-css').val(css || '');
|
|
263
|
+
} catch {
|
|
264
|
+
// non-fatal - textarea stays empty
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**Step 2: Add the Save CSS button handler, after the existing send-test-email handler**
|
|
269
|
+
|
|
270
|
+
After the closing of the `#send-test-email-btn` handler (after line ~115), add:
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
// Save Custom CSS
|
|
274
|
+
$container.find('#save-css-btn').on('click', async () => {
|
|
275
|
+
const css = $container.find('#field-custom-css').val();
|
|
276
|
+
const $btn = $container.find('#save-css-btn');
|
|
277
|
+
$btn.prop('disabled', true);
|
|
278
|
+
try {
|
|
279
|
+
await apiRequest('/settings/custom-css', {
|
|
280
|
+
method: 'PUT',
|
|
281
|
+
body: JSON.stringify({ css })
|
|
282
|
+
});
|
|
283
|
+
E.toast('Custom CSS saved.', { type: 'success' });
|
|
284
|
+
} catch (err) {
|
|
285
|
+
E.toast(err.message || 'Failed to save CSS.', { type: 'error' });
|
|
286
|
+
} finally {
|
|
287
|
+
$btn.prop('disabled', false);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
**Step 3: Verify JS syntax**
|
|
293
|
+
|
|
294
|
+
Run: `node --check admin/js/views/settings.js && echo OK`
|
|
295
|
+
|
|
296
|
+
Expected: `OK`
|
|
297
|
+
|
|
298
|
+
**Step 4: Commit**
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
git add admin/js/views/settings.js
|
|
302
|
+
git commit -m "feat: settings view loads and saves custom CSS tab"
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
### Task 6: Migrate existing CSS data and remove plugin
|
|
308
|
+
|
|
309
|
+
**Files:**
|
|
310
|
+
- Delete: `plugins/custom-css/` (entire directory)
|
|
311
|
+
- Modify: `config/plugins.json`
|
|
312
|
+
|
|
313
|
+
**Step 1: Copy any existing CSS data to core location**
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
cp plugins/custom-css/data/custom.css content/custom.css 2>/dev/null || true
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Step 2: Remove plugin directory**
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
rm -rf plugins/custom-css
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Step 3: Remove entry from config/plugins.json**
|
|
326
|
+
|
|
327
|
+
Remove the `"custom-css"` key. The resulting file should contain only: `example-analytics`, `form-builder`, `domma-effects`.
|
|
328
|
+
|
|
329
|
+
**Step 4: Verify JSON is valid**
|
|
330
|
+
|
|
331
|
+
Run: `node -e "JSON.parse(require('fs').readFileSync('config/plugins.json','utf8')); console.log('OK')"`
|
|
332
|
+
|
|
333
|
+
Expected: `OK`
|
|
334
|
+
|
|
335
|
+
**Step 5: Commit**
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
git add -A
|
|
339
|
+
git commit -m "feat: remove custom-css plugin directory, migrate to core"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Verification
|
|
345
|
+
|
|
346
|
+
1. **Inline style in page source**: Write some CSS to `content/custom.css`, then
|
|
347
|
+
`curl -s http://localhost:4096/ | grep '<style>'` - confirm the style block is present.
|
|
348
|
+
2. **Empty file = no style tag**: Clear the file, re-curl, confirm no `<style>` tag appears.
|
|
349
|
+
3. **Admin tab visible**: Open Site Settings in the admin - 7 tabs should be visible including "Custom CSS".
|
|
350
|
+
4. **Save round-trip**: Enter CSS in the tab, click Save CSS, refresh the page - CSS should persist and appear in the public page source.
|
|
351
|
+
5. **Plugin list**: Admin → Plugins - `custom-css` no longer appears.
|
|
352
|
+
6. **Other plugins unaffected**: `domma-effects`, `form-builder`, `example-analytics` still load normally.
|