@aduptive/strapi-blockscene 1.0.0-alpha.4 → 1.0.0-alpha.6
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/README.md +410 -24
- package/dist/admin.cjs +3754 -496
- package/dist/admin.mjs +3787 -505
- package/dist/server.cjs +859 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,8 @@ module.exports = {
|
|
|
33
33
|
'blocks.hero': {
|
|
34
34
|
label: 'Hero banner',
|
|
35
35
|
description: 'Introduce a page with a prominent title and image.',
|
|
36
|
-
|
|
36
|
+
typology: 'hero', // optional; guessed from the name otherwise
|
|
37
|
+
tags: ['Editorial'],
|
|
37
38
|
keywords: 'heading introduction',
|
|
38
39
|
image: '/block-previews/hero.png',
|
|
39
40
|
},
|
|
@@ -44,19 +45,75 @@ module.exports = {
|
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
Rebuild/restart the admin. Open a content type with a Dynamic Zone. The
|
|
47
|
-
editor panel provides one gallery button per editable, non-full zone
|
|
48
|
-
"Open all blocks" / "Close all blocks"
|
|
48
|
+
editor panel provides one gallery button per editable, non-full zone. Zones
|
|
49
|
+
that already have blocks get "Open all blocks" / "Close all blocks" icon
|
|
50
|
+
buttons right beside the native zone label ("blocks (3)").
|
|
49
51
|
|
|
50
52
|
## Gallery
|
|
51
53
|
|
|
52
|
-
The modal
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
The modal is a block browser (80vw wide):
|
|
55
|
+
|
|
56
|
+
- **Sidebar** (collapsible to icons; remembered per browser): All, Recently
|
|
57
|
+
used and Starred with counts, then the typologies present in the zone.
|
|
58
|
+
- **Top bar**: count (`34 blocks`, or `3 of 34` while filtering), search,
|
|
59
|
+
filter menus Tags, Media and Content (checkboxes; several values in one menu
|
|
60
|
+
match any of them, different menus combine), a "Fields" switch that shows
|
|
61
|
+
each block's attribute list on its card, and a columns slider (1 to 5,
|
|
62
|
+
remembered per browser). Active values show as removable chips with "Clear
|
|
63
|
+
all"; the empty state offers a reset.
|
|
64
|
+
- **Cards**, grouped by typology: facet badges (IMAGE, VIDEO, GALLERY, RICH
|
|
65
|
+
TEXT, LIST, DYNAMIC, FORM), a star and a hover "+" that inserts at once.
|
|
66
|
+
- A click **magnifies** the block: the card grows into a large panel over the
|
|
67
|
+
grid (sidebar and top bar stay usable, the grid dims underneath) and shrinks
|
|
68
|
+
back into its card on close (close button, Esc or a click on the dimmed
|
|
69
|
+
grid). The animation is transform/opacity only, about 250 ms, and is skipped
|
|
70
|
+
under `prefers-reduced-motion: reduce`. The panel shows a large live preview
|
|
71
|
+
with Fit / Mobile / Tablet / Desktop widths (scaled to fit, as in the page
|
|
72
|
+
preview) and a compact strip: label, uid, description, badges, fields (on
|
|
73
|
+
demand), star and Insert. Double click, "+" or Enter on a focused card
|
|
74
|
+
inserts without it.
|
|
75
|
+
|
|
76
|
+
The magnified preview shows the card's thumbnail at once and fades the live
|
|
77
|
+
page in over it once it has loaded. Live source, first match wins:
|
|
78
|
+
|
|
79
|
+
1. **Block preview URL** (`editor.blockPreviewUrl`, Settings, both versions):
|
|
80
|
+
a plain page per block in a plain iframe, no bridge. Placeholders, URL
|
|
81
|
+
encoded: `{uid}`, `{name}` (after the dot), `{category}` (before the dot),
|
|
82
|
+
`{variant}` (`default`) and `{locale}` (the entry's locale, empty when the
|
|
83
|
+
type is not localized). Example:
|
|
84
|
+
`http://localhost:3026/{locale}/block-preview/{name}/{variant}`. Such a
|
|
85
|
+
fixtures route is usually dev-only: leave the option empty on production.
|
|
86
|
+
2. **Page preview route** (Strapi 5: the preview route base URL, else the
|
|
87
|
+
native Preview origin + `/block-preview/page`): the same bridge as the
|
|
88
|
+
whole-page preview, sent one block made from the schema defaults, mode
|
|
89
|
+
`preview`. Read-only: every message except `ready` is ignored.
|
|
90
|
+
3. Otherwise the image only.
|
|
91
|
+
|
|
92
|
+
If the live page neither loads nor says `ready` within 8 s, the image stays
|
|
93
|
+
with a short note. The iframe uses the page preview's sandbox
|
|
94
|
+
(`allow-scripts allow-same-origin`) and `referrerpolicy="no-referrer"`.
|
|
95
|
+
|
|
96
|
+
Stars and recently used blocks are stored per admin user on the server
|
|
97
|
+
(`GET`/`PUT /blockscene/me/prefs`, `{ starred, recent }`, at most 200 and 20
|
|
98
|
+
existing component uids).
|
|
99
|
+
|
|
100
|
+
### Taxonomy
|
|
101
|
+
|
|
102
|
+
Facets are read from each component schema and the components it nests (one
|
|
103
|
+
level): media fields (`image`, `video` by allowed types, `gallery` when
|
|
104
|
+
multiple), `richtext` (rich text, blocks or a CKEditor custom field), `list`
|
|
105
|
+
(repeatable component), `dynamic` (a relation, or a uid with query, archive or
|
|
106
|
+
related) and `form` (uid or display name with form or contact).
|
|
107
|
+
|
|
108
|
+
The typology is one of hero, text, media, listing, cards, cta, form and
|
|
109
|
+
layout, guessed from the component name and display name (hero, banner,
|
|
110
|
+
cover; text, rich, quote, title; image, media, video, gallery, carousel; list,
|
|
111
|
+
query, archive, related, posts, projects; card; cta, button, link; form,
|
|
112
|
+
contact; wrapper, column, grid, divider, spacer, section; else text). Override
|
|
113
|
+
it, and add up to 10 tags (1 to 24 characters), in Settings, Blockscene, or in
|
|
114
|
+
the plugin config: `components[uid].typology` and `components[uid].tags`. A
|
|
115
|
+
Settings value wins over the config. The former `category` config key still
|
|
116
|
+
works: it becomes the block's tag when no tags are set.
|
|
60
117
|
|
|
61
118
|
The native "Add a component to <zone>" button of an editable zone opens this
|
|
62
119
|
gallery as well (the click is intercepted in the capture phase; Strapi's
|
|
@@ -74,7 +131,59 @@ opening or closing the row. The sources are the same as the gallery cards,
|
|
|
74
131
|
minus the wireframe: a block with no image shows nothing, so nothing new is
|
|
75
132
|
invented for blocks that were never captured. The thumbnail is inserted into
|
|
76
133
|
Strapi's own header through the DOM (no Content Manager patch) and is
|
|
77
|
-
restored when Strapi re-renders the list.
|
|
134
|
+
restored when Strapi re-renders the list. Turn it off with the editor option
|
|
135
|
+
`showRowThumbnails: false`.
|
|
136
|
+
|
|
137
|
+
## Row actions
|
|
138
|
+
|
|
139
|
+
Each block header gets a few icons right before Strapi's own delete button
|
|
140
|
+
(inserted through the DOM, like the thumbnails; read-only rows get none):
|
|
141
|
+
|
|
142
|
+
- **Hide on the site** (eye). The block stays in the document and in the
|
|
143
|
+
admin, dimmed with a "Hidden" badge (also in the page preview, which receives
|
|
144
|
+
`hidden: true` for it). What the content API does is the editor option
|
|
145
|
+
`hiddenBlocks`: `strip` (default) removes hidden rows from Dynamic Zones in
|
|
146
|
+
content-API reads (REST and GraphQL, including zones of populated relations
|
|
147
|
+
and components; admin and Content Manager reads always return every row),
|
|
148
|
+
`flag` sends them with the attribute so the frontend decides, `off` removes
|
|
149
|
+
the eye and strips nothing. On a configured group OPEN the eye hides the
|
|
150
|
+
whole group.
|
|
151
|
+
- **Duplicate**. A deep copy right below: ids removed from the row and its
|
|
152
|
+
nested components, new row key, media kept, relations kept (Strapi 5 reads
|
|
153
|
+
the source row's relations from the server and adds its unsaved changes).
|
|
154
|
+
A group OPEN duplicates with its whole range. Option `duplicate`.
|
|
155
|
+
- **Copy / Paste** across pages. The copy icon copies one block; the select
|
|
156
|
+
icon in the zone label shows a checkbox per row, then "Copy selected". The
|
|
157
|
+
blocks are stored in this browser's localStorage (`blockscene:clipboard:v1`,
|
|
158
|
+
with the source content type and locale). "Paste" appears in the zone label
|
|
159
|
+
(under the gallery button for an empty zone) and in the page preview seams.
|
|
160
|
+
Paste is all or nothing: every block must be allowed in the target zone, fit
|
|
161
|
+
its maximum, and groups must be whole; otherwise a notice explains why and the
|
|
162
|
+
form is not changed. Media and relations are kept by id/documentId, so paste
|
|
163
|
+
within the same install. Option `clipboard`.
|
|
164
|
+
- **Confirm delete**. The native delete asks "Delete block …?" first;
|
|
165
|
+
confirming runs Strapi's own removal. On a group marker the dialog says only
|
|
166
|
+
the marker is removed. Option `confirmDelete`.
|
|
167
|
+
|
|
168
|
+
Everything goes through the form: nothing is saved until Save, and undo/redo
|
|
169
|
+
(Strapi 5) covers every action. Strapi 4 supports the same actions; relations
|
|
170
|
+
are copied as the form holds them there (the loaded relations of an opened
|
|
171
|
+
block).
|
|
172
|
+
|
|
173
|
+
**The hidden attribute is a database column.** At register time the plugin adds
|
|
174
|
+
a boolean attribute (like i18n adds `locale`) to every component used in a
|
|
175
|
+
Dynamic Zone: `{ type: 'boolean', default: false, configurable: false }`, so
|
|
176
|
+
Strapi's schema sync creates a `bs_hidden` column in each of those component
|
|
177
|
+
tables on the next start (existing rows read as not hidden). It is never shown
|
|
178
|
+
as an input: the plugin removes it from the components' edit layouts through
|
|
179
|
+
the Content Manager's layout hook (it may be listed in "Configure the view" of
|
|
180
|
+
a component; leave it out of the layout). It is not marked `visible: false`,
|
|
181
|
+
because before Strapi 5.45 the edit view crashes on a value whose attribute the
|
|
182
|
+
admin does not know. Rename it with the plugin config
|
|
183
|
+
`hiddenAttribute: 'myName'`, or set `hiddenAttribute: false` to add nothing (no
|
|
184
|
+
eye, nothing stripped). A component that already has an attribute of that name
|
|
185
|
+
with another type is skipped with a warning. Removing the plugin (or setting
|
|
186
|
+
`false`) leaves the column in place with its data; drop it yourself if you want.
|
|
78
187
|
|
|
79
188
|
## Thumbnail priority
|
|
80
189
|
|
|
@@ -109,9 +218,59 @@ needed for the gallery to pick them up. Reading requires the
|
|
|
109
218
|
- Wireframe palette (background, surfaces, text, accent) with a live preview
|
|
110
219
|
and "Restore default colors". Colors must be `#RRGGBB`.
|
|
111
220
|
- Component list with the effective source, choose/replace image from the
|
|
112
|
-
Media Library, "Use automatic image"
|
|
221
|
+
Media Library, "Use automatic image", the wireframe template, the gallery
|
|
222
|
+
typology ("Automatic" shows the guess) and tags (comma separated).
|
|
113
223
|
- Editor preferences: enhancements on/off, visibility of each collective
|
|
114
224
|
button, initial accordion state and the initial block mode.
|
|
225
|
+
- Version history (Strapi 5): module switch, covered content types, retention
|
|
226
|
+
(see "Version history").
|
|
227
|
+
- Content types: every project type with a Dynamic Zone, each with on/off
|
|
228
|
+
(off leaves its edit view fully native) and, on Strapi 5, the mode its edit
|
|
229
|
+
views open in ("Default" follows the global preview mode) and its visual
|
|
230
|
+
editor sidebar (see below).
|
|
231
|
+
- "Restore project defaults" (or "Reset to defaults" when the project has no
|
|
232
|
+
code defaults), after a confirmation, deletes what was saved here
|
|
233
|
+
(`DELETE /blockscene/settings`, same permission as saving).
|
|
234
|
+
|
|
235
|
+
### Project defaults from code
|
|
236
|
+
|
|
237
|
+
A project can ship its baseline in the plugin config, with the same shape as
|
|
238
|
+
the stored settings (every key optional):
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// config/plugins.js
|
|
242
|
+
module.exports = {
|
|
243
|
+
blockscene: { config: { settings: require('./blockscene.json') } },
|
|
244
|
+
}
|
|
245
|
+
// config/blockscene.json
|
|
246
|
+
{
|
|
247
|
+
"palette": { "accent": "#AA3300" },
|
|
248
|
+
"editor": { "previewMode": "split", "initialState": "open" },
|
|
249
|
+
"components": { "blocks.faq": { "template": "faq", "typology": "text" } },
|
|
250
|
+
"contentTypes": {
|
|
251
|
+
"api::page.page": {
|
|
252
|
+
"sidebarPosition": "right",
|
|
253
|
+
"sidebar": [{ "label": "SEO", "icon": "seo", "open": "drawer", "fields": ["seo"] }]
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The effective settings are the built-in defaults, then the code `settings`,
|
|
260
|
+
then what was saved on the page:
|
|
261
|
+
|
|
262
|
+
- `palette` and `editor`: a saved key wins over the code key by key.
|
|
263
|
+
- `components` and `contentTypes`: a saved entry replaces the code entry for
|
|
264
|
+
that uid as a whole (a saved `api::page.page` entry replaces its code
|
|
265
|
+
sidebar too); other uids keep their code values.
|
|
266
|
+
|
|
267
|
+
Saving stores only what differs from the code defaults, so later changes to the
|
|
268
|
+
code reach every key nobody overrode. A document saved before the project had
|
|
269
|
+
code defaults holds every palette and editor key, and those keep winning until
|
|
270
|
+
"Restore project defaults". The code settings are checked at boot with the same
|
|
271
|
+
rules as `PUT`; if they are invalid a warning names the problem and they are
|
|
272
|
+
ignored (boot continues). `GET /blockscene/settings` returns them as
|
|
273
|
+
`projectDefaults` (null when absent or invalid).
|
|
115
274
|
|
|
116
275
|
### Editor preferences
|
|
117
276
|
|
|
@@ -120,14 +279,36 @@ needed for the gallery to pick them up. Reading requires the
|
|
|
120
279
|
| Editor enhancements enabled | on/off | on |
|
|
121
280
|
| Show "Open all blocks" | yes/no | yes |
|
|
122
281
|
| Show "Close all blocks" | yes/no | yes |
|
|
282
|
+
| Show block thumbnails in the rows (`showRowThumbnails`) | yes/no | yes |
|
|
123
283
|
| Initial accordion state | all closed / all open / remember | all closed |
|
|
284
|
+
| Load rich-text editors on demand (`lazyEditors`, Strapi 5) | yes/no | yes |
|
|
285
|
+
| Custom fields loaded on demand (`lazyFields`, Strapi 5) | up to 20 uids `plugin::x.y` / `global::x` | `["plugin::ckeditor5.CKEditor"]` |
|
|
124
286
|
| Preview route base URL (Strapi 5) | full URL or empty | empty: native Preview origin |
|
|
287
|
+
| Block preview URL | http(s) URL with placeholders, up to 500 characters, or empty | empty: page preview route, else image |
|
|
125
288
|
| Initial preview mode (Strapi 5) | form / side by side / preview | form |
|
|
289
|
+
| Confirm before deleting a block (`confirmDelete`) | yes/no | yes |
|
|
290
|
+
| Duplicate on each block (`duplicate`) | yes/no | yes |
|
|
291
|
+
| Copy and Paste (`clipboard`) | yes/no | yes |
|
|
292
|
+
| Blocks hidden on the site (`hiddenBlocks`) | `strip` / `flag` / `off` | `strip` |
|
|
293
|
+
| Friendly field labels (`friendlyLabels`, see [Field labels](#field-labels)) | yes/no | yes |
|
|
294
|
+
|
|
295
|
+
Every edit view opens in its content type's mode, else the initial preview
|
|
296
|
+
mode. Editors can switch while they edit; the switch is not remembered.
|
|
126
297
|
|
|
127
298
|
The initial state is applied once per document/locale after the blocks
|
|
128
299
|
render; edits, reorders and newly inserted blocks are not re-applied. Hiding a
|
|
129
300
|
button only hides it; native accordion headers keep working.
|
|
130
301
|
|
|
302
|
+
Lazy editors: a custom field listed in `lazyFields` first shows a read-only
|
|
303
|
+
preview of its HTML (same label, hint and error; scripts, frames, styles, event
|
|
304
|
+
handlers and `javascript:` URLs removed) and mounts the real editor on click,
|
|
305
|
+
Enter/Space or keyboard focus, then puts the caret in it. Once mounted it stays
|
|
306
|
+
for that view; closing and reopening the block shows the preview again.
|
|
307
|
+
Disabled fields only show the preview. The wrapper is installed on every
|
|
308
|
+
registered custom field at boot and passes the others straight through; until
|
|
309
|
+
the catalog loads, and when the plugin or the content type is off, every field
|
|
310
|
+
is native.
|
|
311
|
+
|
|
131
312
|
"Remember" stores only the last explicit open all / close all click, as
|
|
132
313
|
`open`/`closed` in the browser's localStorage, keyed by admin URL, user id,
|
|
133
314
|
content type and zone. Another user in the same browser does not inherit it.
|
|
@@ -147,11 +328,62 @@ your frontend serves; the page renders them with its own components and styles
|
|
|
147
328
|
and can ask the admin to open a block, edit a field or pick media. Nothing is
|
|
148
329
|
saved or published by the preview.
|
|
149
330
|
|
|
331
|
+
Side by side, hovering a zone row in the form (open or closed) outlines its
|
|
332
|
+
block in the page, and hovering a block in the page outlines its form row in the
|
|
333
|
+
theme's primary color; hovering never scrolls. When that row is outside the
|
|
334
|
+
visible form, an arrow at the top or bottom edge of the form scrolls to it. The
|
|
335
|
+
divider between form and page drags to resize, takes the arrow keys, Home and
|
|
336
|
+
End, and a double click resets it to half.
|
|
337
|
+
|
|
338
|
+
### Visual editor sidebar
|
|
339
|
+
|
|
340
|
+
Per content type, a bar of buttons on the left, right or bottom edge of the
|
|
341
|
+
visual editor. Each button (label, optional icon) opens some of the document's
|
|
342
|
+
own fields in a modal or a drawer: the native form itself, with every other
|
|
343
|
+
field hidden, so components, repeatable components, media, relations and custom
|
|
344
|
+
fields all keep working. Done, Esc or the backdrop put the form back.
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
// Settings, Blockscene, Content types (or PUT /blockscene/settings, or the code `settings`):
|
|
348
|
+
contentTypes: {
|
|
349
|
+
'api::page.page': {
|
|
350
|
+
sidebarPosition: 'left', // left | right | bottom
|
|
351
|
+
sidebar: [
|
|
352
|
+
{ label: 'Title', icon: 'text', open: 'modal', fields: ['title'] },
|
|
353
|
+
{ label: 'SEO', icon: 'seo', open: 'drawer', fields: ['pageSeo'] },
|
|
354
|
+
],
|
|
355
|
+
},
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Icons: text, tag, seo, settings, image, link, palette, list, globe, info (or
|
|
360
|
+
none). Fields are the type's own top-level attributes; an item naming a field
|
|
361
|
+
removed from the schema is dropped on read. Up to 12 items.
|
|
362
|
+
|
|
363
|
+
The Settings page edits it under each enabled content type: position, then per
|
|
364
|
+
item the label, icon, drawer or modal, the fields (checkboxes), move up/down and
|
|
365
|
+
remove. An item without a label or without fields is flagged and blocks Save.
|
|
366
|
+
Removing every item removes the override.
|
|
367
|
+
|
|
368
|
+
The pane toolbar sets the page width: Fit (the pane), Mobile (390 px), Tablet
|
|
369
|
+
(834 px) or Desktop (1440 px). A device renders at its own width and scales down
|
|
370
|
+
when the pane is narrower, so the desktop layout fits side by side; switching
|
|
371
|
+
never reloads the page. The choice is remembered per browser.
|
|
372
|
+
|
|
150
373
|
Minimal configuration:
|
|
151
374
|
|
|
152
375
|
1. Serve a page that implements the bridge. `examples/page-preview/index.html`
|
|
153
376
|
is a framework-free reference: it answers `ready`/`ping`, renders
|
|
154
377
|
`update-page`, and sends `select`, `focus`, `edit`, `media`, `media-remove`.
|
|
378
|
+
Hover sync is optional: the page sends `{ type: 'hover', key }` (a block
|
|
379
|
+
key, or `null` off blocks) when it changes, and marks the block of the
|
|
380
|
+
admin's `{ type: 'hover', key }` without scrolling. A page that ignores it
|
|
381
|
+
keeps working.
|
|
382
|
+
Row actions: a block hidden on the site arrives with `hidden: true` (the
|
|
383
|
+
example dims it), and `update-page` carries `clipboard` (the number of copied
|
|
384
|
+
blocks, 0 when none or not editable); while it is positive the page may show
|
|
385
|
+
a Paste button in its seams that sends `{ type: 'paste', after }` (a block
|
|
386
|
+
key, or `null` for the start). Both are optional.
|
|
155
387
|
Keep the origin check (`admin` query parameter or your own constant).
|
|
156
388
|
2. Allow the admin origin to embed it (`Content-Security-Policy: frame-ancestors`)
|
|
157
389
|
and allow the page origin in the Strapi admin CSP (`frame-src`).
|
|
@@ -171,14 +403,34 @@ update permission on it. Pending dialogs are dropped when the document or
|
|
|
171
403
|
locale changes.
|
|
172
404
|
|
|
173
405
|
Editing from the page: plain-text areas the page explicitly maps
|
|
174
|
-
(`data-block-field` + `contenteditable="plaintext-only"`) send `edit
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
406
|
+
(`data-block-field` + `contenteditable="plaintext-only"`) send `edit`. In the
|
|
407
|
+
visual editor, a click on any other field or on the block opens the whole block
|
|
408
|
+
over the page: its own native form (every field type, CKEditor, media, nested
|
|
409
|
+
and repeatable components), with the clicked field focused and outlined. The
|
|
410
|
+
page updates while you type; Done, Esc or the backdrop put the block back. Side
|
|
411
|
+
by side focuses the field in the form on the left instead. Media
|
|
178
412
|
fields open the native Media Library. Everything is validated against the schema
|
|
179
413
|
and the zone's edit permission; a published page never receives unsaved values
|
|
180
414
|
by itself. Strapi 4 does not have this panel yet (see `docs/BACKLOG.md`).
|
|
181
415
|
|
|
416
|
+
### Undo and redo
|
|
417
|
+
|
|
418
|
+
The Blockscene panel and the pane toolbar have Undo and Redo buttons (Strapi 5).
|
|
419
|
+
They step through the whole edit view: blocks inserted, removed or moved from the
|
|
420
|
+
gallery, the page, groups or the native actions, and any field edit. Changes
|
|
421
|
+
within 400 ms of each other are one step, so a burst of typing undoes at once;
|
|
422
|
+
up to 100 steps. Shortcuts: Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z and Ctrl+Y, only while
|
|
423
|
+
the focus is outside a text field, select or rich text editor (those keep their
|
|
424
|
+
own undo).
|
|
425
|
+
|
|
426
|
+
Limits: the history lives in the open edit view and starts over when the
|
|
427
|
+
document, the locale or its loaded values change, so a Save clears it. Shortcuts
|
|
428
|
+
pressed inside the preview page are not seen (it is another origin); use the
|
|
429
|
+
buttons there. A custom field that reads its value only once on mount keeps
|
|
430
|
+
showing the old text after an undo until the view reloads; the CKEditor 5
|
|
431
|
+
custom field (@_sh/strapi-plugin-ckeditor) follows the restored value (checked
|
|
432
|
+
on Strapi 5.31).
|
|
433
|
+
|
|
182
434
|
## Layout groups (optional)
|
|
183
435
|
|
|
184
436
|
Some sites keep "wrappers" in the flat Dynamic Zone: an OPEN component, the
|
|
@@ -239,6 +491,137 @@ With a valid map:
|
|
|
239
491
|
Configured groups are stored exactly as before: the flat list of components in
|
|
240
492
|
the zone. Removing the config only removes the group tools and the guard.
|
|
241
493
|
|
|
494
|
+
## Field labels
|
|
495
|
+
|
|
496
|
+
The Content Manager shows each field under its "Configure the view" label, which
|
|
497
|
+
defaults to the raw attribute name (`mobileColumnsCount`). Blockscene rewrites
|
|
498
|
+
the edit view labels, hints and placeholders through the Content Manager's own
|
|
499
|
+
`Admin/CM/pages/EditView/mutate-edit-view-layout` hook (Strapi 5 and 4, the
|
|
500
|
+
same hook the i18n plugin uses), so nothing in the DOM is patched and the
|
|
501
|
+
saved view configuration is never changed. Per field, the first that applies:
|
|
502
|
+
|
|
503
|
+
1. **Project texts** from the plugin config `fields` (below);
|
|
504
|
+
2. **a label set in "Configure the view"** (anything other than the attribute name);
|
|
505
|
+
3. **the humanized name** when "Friendly field labels" is on: `mobileColumnsCount`
|
|
506
|
+
reads "Mobile columns count", `page_seo` "Page seo", acronym runs stay
|
|
507
|
+
(`pageSEO` "Page SEO", `ctaURL` "Cta URL").
|
|
508
|
+
|
|
509
|
+
Description (the hint under the field) and placeholder change only when the
|
|
510
|
+
project texts have them. Texts follow the admin user's interface language
|
|
511
|
+
(`strapi-admin-language`, else English), resolved as: exact locale, then its
|
|
512
|
+
language (`pt-BR` → `pt`), then any variant of that language, then `en`, then
|
|
513
|
+
the first value.
|
|
514
|
+
|
|
515
|
+
```js
|
|
516
|
+
// config/plugins.js
|
|
517
|
+
blockscene: { config: { fields: {
|
|
518
|
+
'api::page.page': {
|
|
519
|
+
pageSeo: { label: { en: 'Search engine settings', 'pt-BR': 'Configurações de SEO' },
|
|
520
|
+
description: { en: 'Title and description shown on Google', 'pt-BR': 'Título e descrição no Google' } },
|
|
521
|
+
},
|
|
522
|
+
'shared.seo': { metaTitle: { placeholder: 'Up to 60 characters' } },
|
|
523
|
+
} } },
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Keys are content type or component uids, then attribute names; each of
|
|
527
|
+
`label` (up to 80 characters), `description` (300) and `placeholder` (120) is a
|
|
528
|
+
string or `{ "<locale>": string }`. The map is validated at boot: an unknown
|
|
529
|
+
key, an empty or too long text, or a malformed locale code logs a warning
|
|
530
|
+
naming it and the whole `fields` config is ignored (labels fall back to the two
|
|
531
|
+
other steps). Entries for a uid or attribute the schema no longer has (a
|
|
532
|
+
renamed or removed field) are skipped with one warning listing them; the rest
|
|
533
|
+
keep working. It is code only, versioned with the
|
|
534
|
+
project; the Settings page has the on/off switch but does not edit texts.
|
|
535
|
+
|
|
536
|
+
To start the file, generate every field of a project with its humanized English
|
|
537
|
+
label from a clone of this repository, then keep what you want to change:
|
|
538
|
+
|
|
539
|
+
```bash
|
|
540
|
+
node scripts/fields-skeleton.mjs ../my-project/backend > ../my-project/backend/config/blockscene-fields.json
|
|
541
|
+
# config/plugins.js: fields: require('./blockscene-fields.json')
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
Limits: the hook runs synchronously and reads the last catalog the admin
|
|
545
|
+
loaded. The first edit or list view of a session starts that request and shows
|
|
546
|
+
native labels; the next layout computed (another document, list → edit, a
|
|
547
|
+
locale switch) has them. Strapi 5 gives the hook no content type uid, so the
|
|
548
|
+
layout is matched by display name and field names; two content types that
|
|
549
|
+
share both are left untouched (component fields always work: they are keyed by
|
|
550
|
+
uid). The switch "Editor enhancements enabled", `BLOCKSCENE_DISABLED` and a
|
|
551
|
+
content type turned off all leave the native labels; any error leaves the
|
|
552
|
+
layout untouched. Changing the interface language applies from the next edit
|
|
553
|
+
view.
|
|
554
|
+
|
|
555
|
+
## Version history (Strapi 5)
|
|
556
|
+
|
|
557
|
+
Off by default. Turn it on in Settings, Blockscene, "Version history" (or from
|
|
558
|
+
code, `settings.history`, see below). Strapi Community has no content history
|
|
559
|
+
(it is a Growth feature); this module records one event per content change and
|
|
560
|
+
keeps a snapshot of the content, so an editor can see what changed and load an
|
|
561
|
+
earlier version back into the form.
|
|
562
|
+
|
|
563
|
+
**What it captures.** Every create, save, publish, unpublish, discard draft and
|
|
564
|
+
delete of the covered content types (all `api::` types by default, or a list)
|
|
565
|
+
made through Strapi's document service: the admin (single and bulk actions),
|
|
566
|
+
the REST and GraphQL APIs, and any plugin or custom code that uses
|
|
567
|
+
`strapi.documents`. One event per affected locale, with who (admin user, API
|
|
568
|
+
token, Users & Permissions user, or `system`), when, the action and a summary
|
|
569
|
+
(blocks added, removed and changed per Dynamic Zone, top-level fields changed)
|
|
570
|
+
against the previous snapshot of the same locale. The snapshot is the stored
|
|
571
|
+
entry with components and Dynamic Zones in full, relations as documentIds and
|
|
572
|
+
media as file ids (a 34-block page is a few KB; the capture adds a few
|
|
573
|
+
milliseconds to a save). A snapshot identical to the previous one is not stored
|
|
574
|
+
again (the event is, with the same hash).
|
|
575
|
+
|
|
576
|
+
**What it does not see.** Writes that bypass the document service: raw
|
|
577
|
+
`strapi.db.query`, knex or SQL, imports that write the database directly. This
|
|
578
|
+
is content activity for editors, not a security audit log.
|
|
579
|
+
|
|
580
|
+
**Failure policy.** A failed capture never blocks a save or a publish: the
|
|
581
|
+
change goes through, the error is logged and the event is marked "Not
|
|
582
|
+
recorded". A failed capture fails a delete: the delete runs in one transaction
|
|
583
|
+
with its events, so nothing is deleted without its last version (a bulk delete
|
|
584
|
+
is rolled back whole). `BLOCKSCENE_DISABLED=true` or the module switch off stop
|
|
585
|
+
all capture. The plugin never records its own content types.
|
|
586
|
+
|
|
587
|
+
**In the edit view.** The Blockscene side panel gets a History section (saved
|
|
588
|
+
documents of covered types, also on types without a Dynamic Zone): the
|
|
589
|
+
versions of the document in the current locale, newest first. Selecting one
|
|
590
|
+
shows a block-level diff against the form (relations are not compared) and
|
|
591
|
+
"Load this version", which puts the version into the form the way undo does:
|
|
592
|
+
nothing is written until the editor saves, so validation, permissions and
|
|
593
|
+
lifecycles apply as for any edit, and undo reverts the load. Components and
|
|
594
|
+
blocks come back as new rows; relations become the connect/disconnect change
|
|
595
|
+
from what the document has now; fields the editor may not update, fields the
|
|
596
|
+
schema no longer has, blocks whose component is no longer allowed, and media or
|
|
597
|
+
related entries that no longer exist are left out and listed.
|
|
598
|
+
|
|
599
|
+
**Permission.** `Blockscene: Read version history` (`history.read`), plus read
|
|
600
|
+
access to the content type in the Content Manager. Snapshots hold removed and
|
|
601
|
+
unpublished text, so the section is hidden without it. Admin API:
|
|
602
|
+
`GET /blockscene/history/:uid/:documentId?locale=` (the latest 100 events, no
|
|
603
|
+
snapshots) and `GET /blockscene/history-events/:id` (one event, its snapshot and
|
|
604
|
+
the media and relation targets that still exist).
|
|
605
|
+
|
|
606
|
+
**Retention.** Snapshots are kept `retentionDays` (90) and at most
|
|
607
|
+
`maxSnapshots` (100) per document, newest first; events without a snapshot are
|
|
608
|
+
kept `eventDays` (365, at least `retentionDays`). A cron job added by the plugin
|
|
609
|
+
runs nightly at 03:00 server time, in batches of 500; it only empties snapshots
|
|
610
|
+
and deletes events, never media files, and running it on several instances is
|
|
611
|
+
harmless.
|
|
612
|
+
|
|
613
|
+
```js
|
|
614
|
+
// config/plugins.js
|
|
615
|
+
blockscene: { config: { settings: { history: { enabled: true, contentTypes: ['api::page.page', 'api::post.post'],
|
|
616
|
+
retentionDays: 90, maxSnapshots: 100, eventDays: 365 } } } }
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
Events live in the `blockscene_events` table (content type
|
|
620
|
+
`plugin::blockscene.event`, hidden from the Content Manager and the Content-Type
|
|
621
|
+
Builder). Removing the plugin, or installing a Blockscene version older than
|
|
622
|
+
the one that added history, lets Strapi drop that table and every recorded
|
|
623
|
+
version on the next start: back up `blockscene_events` first if you need it.
|
|
624
|
+
|
|
242
625
|
## Languages
|
|
243
626
|
|
|
244
627
|
All plugin chrome (gallery, settings, page preview, editor dialogs, diagnostics)
|
|
@@ -318,14 +701,17 @@ installs without overrides, not a promise for every minor in between. Strapi
|
|
|
318
701
|
- Authenticated admin catalog endpoint exposes only supported metadata, resolved
|
|
319
702
|
override URLs, palette and editor preferences; never the whole config.
|
|
320
703
|
- Top-level Dynamic Zones only. Conditional fields are omitted conservatively.
|
|
321
|
-
- "Open all" / "Close all" drive the native accordions
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
704
|
+
- "Open all" / "Close all" drive the native accordions without touching the
|
|
705
|
+
whole list at once: open all opens the rows in and near the visible area, a
|
|
706
|
+
few per frame, and the others as they approach while scrolling (until Close
|
|
707
|
+
all or leaving the document); close all closes the visible rows at once and
|
|
708
|
+
the rest in idle time. With lazy editors, on a 34-block page with CKEditor
|
|
709
|
+
fields (Strapi 5.31) the longest pause went from about 2.9 s to 0.14 s on
|
|
710
|
+
open all and from 1.6 s to 0.14 s on close all.
|
|
326
711
|
- No screenshot server, no hourly job, no in-editor rendered preview.
|
|
327
712
|
- Removing the plugin leaves native content intact; remove its config entry and
|
|
328
|
-
rebuild. No plugin data migration is needed.
|
|
713
|
+
rebuild. No plugin data migration is needed. The "hide on the site" column
|
|
714
|
+
(see Row actions) stays in the component tables until you drop it.
|
|
329
715
|
|
|
330
716
|
Configuration edits require a server restart. Backend URL/prefix deployments
|
|
331
717
|
should set `previewBaseUrl` explicitly. HTTP(S) image hosts must also be allowed
|
|
@@ -336,7 +722,7 @@ uploads share an origin.
|
|
|
336
722
|
## Development
|
|
337
723
|
|
|
338
724
|
- `admin/`: shared gallery, settings page, wireframes and version-specific adapters.
|
|
339
|
-
- `server/`: settings store, validation, permissions, the catalog endpoint and the layout-group publish guard (`groups.js` is shared with the admin).
|
|
725
|
+
- `server/`: settings store, validation, permissions, the catalog endpoint and the layout-group publish guard (`groups.js` is shared with the admin); `history.js` and `diff.js` for version history (`diff.js` is shared with the admin).
|
|
340
726
|
- `admin/translations/`: one flat catalogue per admin locale (English is the source of truth).
|
|
341
727
|
- `scripts/capture-previews.mjs`: local thumbnail capture.
|
|
342
728
|
- `packages/strapi4`, `packages/strapi5`: independently installable distributions.
|