@aduptive/strapi-blockscene 1.0.0-alpha.4 → 1.0.0-alpha.5
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 +271 -23
- package/dist/admin.cjs +3258 -491
- package/dist/admin.mjs +3288 -498
- package/dist/server.cjs +357 -33
- package/package.json +1 -1
package/dist/admin.cjs
CHANGED
|
@@ -4,6 +4,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
7
11
|
var __export = (target, all) => {
|
|
8
12
|
for (var name in all)
|
|
9
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -25,6 +29,113 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
29
|
mod
|
|
26
30
|
));
|
|
27
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
33
|
+
|
|
34
|
+
// server/groups.js
|
|
35
|
+
var require_groups = __commonJS({
|
|
36
|
+
"server/groups.js"(exports, module2) {
|
|
37
|
+
"use strict";
|
|
38
|
+
var UID = /^[a-z0-9-]+\.[a-z0-9-]+$/;
|
|
39
|
+
function safeGroups2(value, knownUids) {
|
|
40
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
41
|
+
const out = {};
|
|
42
|
+
for (const [open, close] of Object.entries(value)) {
|
|
43
|
+
if (!UID.test(open) || typeof close !== "string" || !UID.test(close) || open === close) continue;
|
|
44
|
+
if (knownUids && (!knownUids.includes(open) || !knownUids.includes(close))) continue;
|
|
45
|
+
out[open] = close;
|
|
46
|
+
}
|
|
47
|
+
for (const close of Object.values(out)) if (out[close]) return null;
|
|
48
|
+
return Object.keys(out).length ? out : null;
|
|
49
|
+
}
|
|
50
|
+
var uidOf = (row) => typeof row?.__component === "string" ? row.__component : "";
|
|
51
|
+
var isOpener2 = (row, g) => Boolean(g) && Object.prototype.hasOwnProperty.call(g, uidOf(row));
|
|
52
|
+
var isClose2 = (row, g) => Boolean(g) && Object.values(g).includes(uidOf(row));
|
|
53
|
+
var blockKey2 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
|
|
54
|
+
function validateGroups3(rows, g) {
|
|
55
|
+
const errors = [];
|
|
56
|
+
if (!g || !Array.isArray(rows)) return errors;
|
|
57
|
+
const stack = [];
|
|
58
|
+
rows.forEach((row, index) => {
|
|
59
|
+
const uid = uidOf(row);
|
|
60
|
+
if (isOpener2(row, g)) {
|
|
61
|
+
stack.push({ index, uid, close: g[uid] });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!isClose2(row, g)) return;
|
|
65
|
+
const top = stack[stack.length - 1];
|
|
66
|
+
if (!top) errors.push({ code: "closeBeforeOpen", index, uid });
|
|
67
|
+
else if (top.close !== uid) errors.push({ code: "mismatch", index, uid, expected: top.close, open: top.uid, openIndex: top.index });
|
|
68
|
+
else stack.pop();
|
|
69
|
+
});
|
|
70
|
+
for (const open of stack) errors.push({ code: "unclosed", index: open.index, uid: open.uid, expected: open.close });
|
|
71
|
+
return errors;
|
|
72
|
+
}
|
|
73
|
+
function groupRange3(rows, start, g) {
|
|
74
|
+
const stack = [g[uidOf(rows[start])]];
|
|
75
|
+
for (let i = start + 1; i < rows.length; i++) {
|
|
76
|
+
const row = rows[i];
|
|
77
|
+
if (isOpener2(row, g)) stack.push(g[uidOf(row)]);
|
|
78
|
+
else if (isClose2(row, g) && uidOf(row) === stack[stack.length - 1]) {
|
|
79
|
+
stack.pop();
|
|
80
|
+
if (!stack.length) return [start, i];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return [start, rows.length - 1];
|
|
84
|
+
}
|
|
85
|
+
function groupRows2(rows, g, depth = 0, offset = 0) {
|
|
86
|
+
const out = [];
|
|
87
|
+
let i = 0;
|
|
88
|
+
while (i < rows.length) {
|
|
89
|
+
const row = rows[i];
|
|
90
|
+
if (isOpener2(row, g)) {
|
|
91
|
+
const [, end] = groupRange3(rows, i, g);
|
|
92
|
+
const closed = uidOf(rows[end]) === g[uidOf(row)] && end > i;
|
|
93
|
+
out.push({
|
|
94
|
+
type: "group",
|
|
95
|
+
key: blockKey2(row),
|
|
96
|
+
closeKey: closed ? blockKey2(rows[end]) : null,
|
|
97
|
+
row,
|
|
98
|
+
index: offset + i,
|
|
99
|
+
depth,
|
|
100
|
+
children: groupRows2(rows.slice(i + 1, closed ? end : end + 1), g, depth + 1, offset + i + 1)
|
|
101
|
+
});
|
|
102
|
+
i = end + 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
out.push({ type: "block", key: blockKey2(row), row, index: offset + i, depth, stray: isClose2(row, g) });
|
|
106
|
+
i++;
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
function topLevelRanges2(rows, g) {
|
|
111
|
+
const ranges = [];
|
|
112
|
+
let i = 0;
|
|
113
|
+
while (i < rows.length) {
|
|
114
|
+
const end = isOpener2(rows[i], g) ? groupRange3(rows, i, g)[1] : i;
|
|
115
|
+
ranges.push([i, end]);
|
|
116
|
+
i = end + 1;
|
|
117
|
+
}
|
|
118
|
+
return ranges;
|
|
119
|
+
}
|
|
120
|
+
function moveGroup2(rows, key, direction, g) {
|
|
121
|
+
if (!g) return null;
|
|
122
|
+
const ranges = topLevelRanges2(rows, g);
|
|
123
|
+
const at = ranges.findIndex(([s]) => blockKey2(rows[s]) === String(key));
|
|
124
|
+
const to = at + (direction === "up" ? -1 : 1);
|
|
125
|
+
if (at < 0 || to < 0 || to >= ranges.length) return null;
|
|
126
|
+
const [a, b] = direction === "up" ? [ranges[to], ranges[at]] : [ranges[at], ranges[to]];
|
|
127
|
+
return [...rows.slice(0, a[0]), ...rows.slice(b[0], b[1] + 1), ...rows.slice(a[0], a[1] + 1), ...rows.slice(b[1] + 1)];
|
|
128
|
+
}
|
|
129
|
+
function removeGroup2(rows, key, g) {
|
|
130
|
+
if (!g) return null;
|
|
131
|
+
const start = rows.findIndex((row) => blockKey2(row) === String(key));
|
|
132
|
+
if (start < 0 || !isOpener2(rows[start], g)) return null;
|
|
133
|
+
const [, end] = groupRange3(rows, start, g);
|
|
134
|
+
return [...rows.slice(0, start), ...rows.slice(end + 1)];
|
|
135
|
+
}
|
|
136
|
+
module2.exports = { safeGroups: safeGroups2, validateGroups: validateGroups3, groupRange: groupRange3, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey2, isOpener: isOpener2, isClose: isClose2 };
|
|
137
|
+
}
|
|
138
|
+
});
|
|
28
139
|
|
|
29
140
|
// admin/strapi4.tsx
|
|
30
141
|
var strapi4_exports = {};
|
|
@@ -32,18 +143,42 @@ __export(strapi4_exports, {
|
|
|
32
143
|
default: () => strapi4_default
|
|
33
144
|
});
|
|
34
145
|
module.exports = __toCommonJS(strapi4_exports);
|
|
35
|
-
var
|
|
36
|
-
var
|
|
146
|
+
var React8 = __toESM(require("react"));
|
|
147
|
+
var import_design_system5 = require("@strapi/design-system");
|
|
37
148
|
var import_helper_plugin = require("@strapi/helper-plugin");
|
|
38
149
|
|
|
39
150
|
// admin/Gallery.tsx
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
151
|
+
var React4 = __toESM(require("react"));
|
|
152
|
+
var import_react_dom3 = require("react-dom");
|
|
153
|
+
var import_design_system2 = require("@strapi/design-system");
|
|
154
|
+
var import_styled_components3 = __toESM(require("styled-components"));
|
|
44
155
|
|
|
45
156
|
// admin/model.mjs
|
|
46
157
|
var import_fractional_indexing = require("fractional-indexing");
|
|
158
|
+
function componentDefaults(schema, components, stack = []) {
|
|
159
|
+
if (!schema || stack.includes(schema))
|
|
160
|
+
throw new Error("Invalid recursive component defaults");
|
|
161
|
+
const row = {};
|
|
162
|
+
for (const [name, attr] of Object.entries(schema.attributes || {})) {
|
|
163
|
+
if (Object.hasOwn(attr, "default")) {
|
|
164
|
+
const value = structuredClone(attr.default);
|
|
165
|
+
if (attr.type === "password") row[name] = "";
|
|
166
|
+
else if (attr.type === "relation")
|
|
167
|
+
row[name] = { connect: [], disconnect: [] };
|
|
168
|
+
else if (value !== null || attr.type === "boolean") row[name] = value;
|
|
169
|
+
} else if (attr.type === "component" && attr.required) {
|
|
170
|
+
const create = () => componentDefaults(components[attr.component], components, [
|
|
171
|
+
...stack,
|
|
172
|
+
schema
|
|
173
|
+
]);
|
|
174
|
+
if (attr.repeatable) {
|
|
175
|
+
const keys = (0, import_fractional_indexing.generateNKeysBetween)(null, null, attr.min || 0);
|
|
176
|
+
row[name] = keys.map((key) => ({ ...create(), __temp_key__: key }));
|
|
177
|
+
} else row[name] = create();
|
|
178
|
+
} else if (attr.type === "dynamiczone" && attr.required) row[name] = [];
|
|
179
|
+
}
|
|
180
|
+
return row;
|
|
181
|
+
}
|
|
47
182
|
function editableZones(schema, values, canEdit, disabled = false) {
|
|
48
183
|
if (disabled) return [];
|
|
49
184
|
return Object.entries(schema?.attributes || {}).filter(
|
|
@@ -76,6 +211,18 @@ function candidatesFor(uid, meta = {}, config = {}) {
|
|
|
76
211
|
`${base}/${encodeURIComponent(uid)}.webp${version}`
|
|
77
212
|
].filter(Boolean);
|
|
78
213
|
}
|
|
214
|
+
function blockPreviewSrc(template, uid, { variant = "default", locale = "" } = {}) {
|
|
215
|
+
if (!template || !uid) return null;
|
|
216
|
+
const dot = uid.indexOf(".");
|
|
217
|
+
const values = { uid, name: uid.slice(dot + 1), category: dot < 0 ? "" : uid.slice(0, dot), variant, locale };
|
|
218
|
+
try {
|
|
219
|
+
const url = new URL(template.replace(/\{(uid|name|category|variant|locale)\}/g, (_, key) => encodeURIComponent(values[key] || "")));
|
|
220
|
+
url.pathname = url.pathname.replace(/\/{2,}/g, "/");
|
|
221
|
+
return ["http:", "https:"].includes(url.protocol) ? url.href : null;
|
|
222
|
+
} catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
79
226
|
var SYSTEM_FIELDS = [
|
|
80
227
|
"id",
|
|
81
228
|
"documentId",
|
|
@@ -89,49 +236,59 @@ var SYSTEM_FIELDS = [
|
|
|
89
236
|
];
|
|
90
237
|
var fieldType = (attr) => attr?.type === "customField" ? String(attr.customField || "").includes("CKEditor") ? "richtext" : "customField" : attr?.type || "unknown";
|
|
91
238
|
var fieldsOf = (schema) => Object.entries(schema?.attributes || {}).filter(([name]) => !SYSTEM_FIELDS.includes(name)).map(([name, attr]) => ({ name, type: fieldType(attr) }));
|
|
92
|
-
var
|
|
93
|
-
var
|
|
239
|
+
var TYPOLOGIES = ["hero", "text", "media", "listing", "cards", "cta", "form", "layout"];
|
|
240
|
+
var FACETS = { media: ["image", "video", "gallery"], content: ["richtext", "list", "dynamic", "form"] };
|
|
241
|
+
var typologyRank = (t) => TYPOLOGIES.indexOf(t) + 1 || 99;
|
|
94
242
|
var pickable = (zone, config) => {
|
|
95
243
|
const closers = Object.values(config.groups || {});
|
|
96
244
|
return zone.components.filter((uid) => !closers.includes(uid));
|
|
97
245
|
};
|
|
98
|
-
function
|
|
246
|
+
function entryOf(uid, schema, config) {
|
|
247
|
+
const meta = config.components?.[uid] || {};
|
|
248
|
+
return {
|
|
249
|
+
uid,
|
|
250
|
+
label: meta.label || schema.info?.displayName || uid,
|
|
251
|
+
description: meta.description || schema.info?.description || "",
|
|
252
|
+
typology: meta.typology || "text",
|
|
253
|
+
facets: meta.facets || [],
|
|
254
|
+
tags: meta.tags || [],
|
|
255
|
+
keywords: meta.keywords || "",
|
|
256
|
+
fields: fieldsOf(schema),
|
|
257
|
+
candidates: candidatesFor(uid, meta, config),
|
|
258
|
+
template: meta.template || "generic"
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
var allEntries = (zone, components, config) => pickable(zone, config).flatMap((uid) => components[uid] ? [entryOf(uid, components[uid], config)] : []);
|
|
262
|
+
function entriesFor(zone, components, config, query, filter = {}) {
|
|
99
263
|
const needle = query.trim().toLocaleLowerCase();
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const entry = {
|
|
105
|
-
uid,
|
|
106
|
-
label: meta.label || schema.info?.displayName || uid,
|
|
107
|
-
description: meta.description || schema.info?.description || "",
|
|
108
|
-
category: categoryOf(uid, schema, meta),
|
|
109
|
-
fields: fieldsOf(schema),
|
|
110
|
-
candidates: candidatesFor(uid, meta, config),
|
|
111
|
-
template: meta.template || "generic"
|
|
112
|
-
};
|
|
113
|
-
if (category !== "all" && entry.category !== category) return [];
|
|
114
|
-
return `${entry.label} ${entry.description} ${entry.category} ${uid} ${meta.keywords || ""}`.toLocaleLowerCase().includes(needle) ? [entry] : [];
|
|
115
|
-
}).sort(
|
|
116
|
-
(a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label)
|
|
117
|
-
);
|
|
264
|
+
const any = (picked, values) => !picked?.length || picked.some((value) => values.includes(value));
|
|
265
|
+
return allEntries(zone, components, config).filter(
|
|
266
|
+
(entry) => (!filter.typology || entry.typology === filter.typology) && (!filter.uids || filter.uids.includes(entry.uid)) && any(filter.tags, entry.tags) && any(filter.media, entry.facets) && any(filter.content, entry.facets) && `${entry.label} ${entry.description} ${entry.typology} ${entry.tags.join(" ")} ${entry.uid} ${entry.keywords}`.toLocaleLowerCase().includes(needle)
|
|
267
|
+
).sort((a, b) => typologyRank(a.typology) - typologyRank(b.typology) || a.label.localeCompare(b.label));
|
|
118
268
|
}
|
|
119
|
-
function
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return
|
|
269
|
+
function optionsFor(zone, components, config) {
|
|
270
|
+
const count = (values) => {
|
|
271
|
+
const counts = /* @__PURE__ */ new Map();
|
|
272
|
+
for (const value of values) counts.set(value, (counts.get(value) || 0) + 1);
|
|
273
|
+
return [...counts.entries()];
|
|
274
|
+
};
|
|
275
|
+
const entries = allEntries(zone, components, config);
|
|
276
|
+
const facets = entries.flatMap((entry) => entry.facets);
|
|
277
|
+
return {
|
|
278
|
+
total: entries.length,
|
|
279
|
+
uids: entries.map((entry) => entry.uid),
|
|
280
|
+
typologies: count(entries.map((entry) => entry.typology)).sort(([a], [b]) => typologyRank(a) - typologyRank(b)),
|
|
281
|
+
tags: count(entries.flatMap((entry) => entry.tags)).sort(([a], [b]) => a.localeCompare(b)),
|
|
282
|
+
media: count(facets.filter((facet) => FACETS.media.includes(facet))),
|
|
283
|
+
content: count(facets.filter((facet) => FACETS.content.includes(facet)))
|
|
284
|
+
};
|
|
128
285
|
}
|
|
129
286
|
function groupEntries(entries) {
|
|
130
287
|
const map = /* @__PURE__ */ new Map();
|
|
131
288
|
for (const entry of entries)
|
|
132
|
-
map.set(entry.
|
|
133
|
-
return [...map.entries()].map(([
|
|
134
|
-
|
|
289
|
+
map.set(entry.typology, [...map.get(entry.typology) || [], entry]);
|
|
290
|
+
return [...map.entries()].map(([typology, items]) => ({
|
|
291
|
+
typology,
|
|
135
292
|
entries: items
|
|
136
293
|
}));
|
|
137
294
|
}
|
|
@@ -139,18 +296,18 @@ function memoryKey({ base = "", userId, contentType, zone }) {
|
|
|
139
296
|
if (!userId || !contentType || !zone) return null;
|
|
140
297
|
return `blockscene:v1:${base}:${userId}:${contentType}:${zone}`;
|
|
141
298
|
}
|
|
142
|
-
function readMemory(
|
|
299
|
+
function readMemory(storage3, key) {
|
|
143
300
|
try {
|
|
144
|
-
const value = key &&
|
|
301
|
+
const value = key && storage3?.getItem(key);
|
|
145
302
|
return value === "open" || value === "closed" ? value : null;
|
|
146
303
|
} catch {
|
|
147
304
|
return null;
|
|
148
305
|
}
|
|
149
306
|
}
|
|
150
|
-
function writeMemory(
|
|
307
|
+
function writeMemory(storage3, key, value) {
|
|
151
308
|
try {
|
|
152
309
|
if (key && (value === "open" || value === "closed"))
|
|
153
|
-
|
|
310
|
+
storage3?.setItem(key, value);
|
|
154
311
|
} catch {
|
|
155
312
|
}
|
|
156
313
|
}
|
|
@@ -160,6 +317,117 @@ function initialState(editor, remembered) {
|
|
|
160
317
|
return "closed";
|
|
161
318
|
}
|
|
162
319
|
|
|
320
|
+
// admin/preview.mjs
|
|
321
|
+
var import_groups = __toESM(require_groups(), 1);
|
|
322
|
+
var PROTOCOL = "blockscene:page-preview:v1";
|
|
323
|
+
var TEXT_TYPES = ["string", "text"];
|
|
324
|
+
var RICH_TYPES = ["richtext", "blocks", "customField"];
|
|
325
|
+
var EDITABLE_TYPES = [...TEXT_TYPES, ...RICH_TYPES];
|
|
326
|
+
var SCALAR = ["string", "text", "richtext", "email", "enumeration", "integer", "biginteger", "float", "decimal", "boolean", "date", "datetime", "time", "json", "blocks", "uid", "customField"];
|
|
327
|
+
var blockKey = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
|
|
328
|
+
function projectRow(row, schema, components, cmsOrigin, depth = 0) {
|
|
329
|
+
if (!row || !schema || depth > 3) return null;
|
|
330
|
+
const out = {};
|
|
331
|
+
for (const [name, attr] of Object.entries(schema.attributes || {})) {
|
|
332
|
+
const value = row[name];
|
|
333
|
+
if (attr.type === "password" || attr.type === "relation" || attr.private) continue;
|
|
334
|
+
if (SCALAR.includes(attr.type)) {
|
|
335
|
+
if (value !== void 0) out[name] = typeof value === "string" ? value.slice(0, 2e5) : value;
|
|
336
|
+
} else if (attr.type === "media") {
|
|
337
|
+
const files = (attr.multiple ? Array.isArray(value) ? value : [] : value ? [value] : []).map((file) => projectMedia(file, cmsOrigin)).filter(Boolean);
|
|
338
|
+
out[name] = attr.multiple ? files : files[0] || null;
|
|
339
|
+
} else if (attr.type === "component") {
|
|
340
|
+
const child = components?.[attr.component];
|
|
341
|
+
out[name] = attr.repeatable ? (Array.isArray(value) ? value : []).slice(0, 100).map((item, i) => ({ ...projectRow(item, child, components, cmsOrigin, depth + 1), __key: blockKey(item) ?? String(i) })) : projectRow(value, child, components, cmsOrigin, depth + 1);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
function projectMedia(file, cmsOrigin) {
|
|
347
|
+
if (!file || typeof file.url !== "string") return null;
|
|
348
|
+
try {
|
|
349
|
+
const url = new URL(file.url, cmsOrigin);
|
|
350
|
+
if (!["http:", "https:"].includes(url.protocol)) return null;
|
|
351
|
+
return { url: url.href, alternativeText: String(file.alternativeText || ""), caption: String(file.caption || ""), width: Number(file.width) || 0, height: Number(file.height) || 0, mime: String(file.mime || "") };
|
|
352
|
+
} catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function editableFields(uid, row, components) {
|
|
357
|
+
const schema = components?.[uid];
|
|
358
|
+
const out = [];
|
|
359
|
+
const SYSTEM = ["id", "documentId", "locale", "createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "localizations", "__component", "__temp_key__"];
|
|
360
|
+
const push = (name, attr, label) => {
|
|
361
|
+
if (!SYSTEM.includes(name.split(".").pop()) && attr?.private !== true && EDITABLE_TYPES.includes(attr?.type)) out.push({ name, type: attr.type, label });
|
|
362
|
+
};
|
|
363
|
+
for (const [name, attr] of Object.entries(schema?.attributes || {})) {
|
|
364
|
+
if (attr.type === "component" && attr.repeatable) {
|
|
365
|
+
(Array.isArray(row?.[name]) ? row[name] : []).slice(0, 50).forEach((_, i) => {
|
|
366
|
+
for (const [child, childAttr] of Object.entries(components?.[attr.component]?.attributes || {})) push(`${name}.${i}.${child}`, childAttr, `${name} ${i + 1} \xB7 ${child}`);
|
|
367
|
+
});
|
|
368
|
+
} else push(name, attr, name);
|
|
369
|
+
}
|
|
370
|
+
return out;
|
|
371
|
+
}
|
|
372
|
+
function mediaFields(uid, row, components) {
|
|
373
|
+
const media = {};
|
|
374
|
+
for (const [name, attr] of Object.entries(components?.[uid]?.attributes || {})) {
|
|
375
|
+
if (attr.type === "media" && attr.private !== true) media[name] = { required: attr.required === true, multiple: attr.multiple === true, present: attr.multiple ? Array.isArray(row?.[name]) && row[name].length > 0 : Boolean(row?.[name]) };
|
|
376
|
+
}
|
|
377
|
+
return media;
|
|
378
|
+
}
|
|
379
|
+
function projectPage(rows, components, cmsOrigin, hidden = null) {
|
|
380
|
+
return (Array.isArray(rows) ? rows : []).slice(0, 200).flatMap((row, index) => {
|
|
381
|
+
const uid = row?.__component;
|
|
382
|
+
const key = blockKey(row);
|
|
383
|
+
const schema = components?.[uid];
|
|
384
|
+
if (!uid || key == null || !schema) return [];
|
|
385
|
+
return [{
|
|
386
|
+
key,
|
|
387
|
+
index,
|
|
388
|
+
uid,
|
|
389
|
+
label: schema.info?.displayName || uid,
|
|
390
|
+
data: projectRow(row, schema, components, cmsOrigin),
|
|
391
|
+
fields: editableFields(uid, row, components),
|
|
392
|
+
media: mediaFields(uid, row, components),
|
|
393
|
+
...hidden && row[hidden] === true && { hidden: true }
|
|
394
|
+
}];
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
function isPreviewMessage(event, origin, source, channel, type) {
|
|
398
|
+
return event.origin === origin && event.source === source && event.data?.protocol === PROTOCOL && event.data?.channel === channel && event.data?.type === type;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// admin/devices.ts
|
|
402
|
+
var React = __toESM(require("react"));
|
|
403
|
+
var DEVICES = { fit: 0, mobile: 390, tablet: 834, desktop: 1440 };
|
|
404
|
+
function useStageSize(el) {
|
|
405
|
+
const [size, setSize] = React.useState({ width: 0, height: 0 });
|
|
406
|
+
React.useEffect(() => {
|
|
407
|
+
if (!el) return;
|
|
408
|
+
const measure = () => setSize({ width: el.clientWidth, height: el.clientHeight });
|
|
409
|
+
measure();
|
|
410
|
+
const observer = "ResizeObserver" in window ? new ResizeObserver(measure) : null;
|
|
411
|
+
observer?.observe(el);
|
|
412
|
+
return () => observer?.disconnect();
|
|
413
|
+
}, [el]);
|
|
414
|
+
return size;
|
|
415
|
+
}
|
|
416
|
+
var frameStyle = (device, stage) => {
|
|
417
|
+
const width = DEVICES[device];
|
|
418
|
+
if (!width || !stage.width) return { left: 0, width: "100%", height: "100%" };
|
|
419
|
+
const scale = Math.min(1, stage.width / width);
|
|
420
|
+
return { left: Math.max(0, (stage.width - width * scale) / 2), width, height: stage.height / scale, transform: `scale(${scale})` };
|
|
421
|
+
};
|
|
422
|
+
var stageBackground = (theme) => {
|
|
423
|
+
const line = theme?.colors?.neutral150 || "#eaeaef";
|
|
424
|
+
return {
|
|
425
|
+
backgroundColor: theme?.colors?.neutral100 || "#f6f6f9",
|
|
426
|
+
backgroundImage: `linear-gradient(${line} 1px, transparent 1px), linear-gradient(90deg, ${line} 1px, transparent 1px)`,
|
|
427
|
+
backgroundSize: "24px 24px"
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
|
|
163
431
|
// admin/accordions.mjs
|
|
164
432
|
function zoneLists(root = document) {
|
|
165
433
|
return [...root.querySelectorAll("ol[aria-describedby]")].filter((list) => list.querySelector(":scope > li button[aria-expanded]"));
|
|
@@ -172,28 +440,100 @@ function findZoneList(label, root = document) {
|
|
|
172
440
|
function toggles(list) {
|
|
173
441
|
return [...list.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
|
|
174
442
|
}
|
|
443
|
+
function planRows(rects, view, margin = 0) {
|
|
444
|
+
const now = [], later = [];
|
|
445
|
+
const gap = (r) => Math.max(view.top - margin - r.bottom, r.top - view.bottom - margin, 0);
|
|
446
|
+
rects.forEach((r, i) => (gap(r) === 0 ? now : later).push(i));
|
|
447
|
+
later.sort((a, b) => gap(rects[a]) - gap(rects[b]));
|
|
448
|
+
return { now, later };
|
|
449
|
+
}
|
|
450
|
+
function scroller(el) {
|
|
451
|
+
for (let node = el?.parentElement; node && node !== document.body; node = node.parentElement) {
|
|
452
|
+
const { overflowY } = getComputedStyle(node);
|
|
453
|
+
if ((overflowY === "auto" || overflowY === "scroll") && node.scrollHeight > node.clientHeight) return node;
|
|
454
|
+
}
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
var jobs = /* @__PURE__ */ new Map();
|
|
458
|
+
function stopAll() {
|
|
459
|
+
for (const stop of jobs.values()) stop();
|
|
460
|
+
jobs.clear();
|
|
461
|
+
}
|
|
462
|
+
var PER_FRAME = 3;
|
|
463
|
+
var idle = (run) => typeof requestIdleCallback === "function" ? requestIdleCallback(run, { timeout: 300 }) : setTimeout(() => run({ timeRemaining: () => 8 }), 16);
|
|
464
|
+
var frame = (run) => typeof requestAnimationFrame === "function" ? requestAnimationFrame(run) : setTimeout(run, 16);
|
|
175
465
|
function setAll(list, open, batch = (run) => run()) {
|
|
176
|
-
|
|
466
|
+
jobs.get(list)?.();
|
|
467
|
+
jobs.delete(list);
|
|
468
|
+
const header = (li) => li.querySelector("button[aria-expanded]");
|
|
469
|
+
const differs = (li) => {
|
|
470
|
+
const b = li.isConnected && header(li);
|
|
471
|
+
return b && b.getAttribute("aria-expanded") === "true" !== open ? b : null;
|
|
472
|
+
};
|
|
473
|
+
const click = (rows2) => {
|
|
474
|
+
const buttons = rows2.map(differs).filter(Boolean);
|
|
475
|
+
if (buttons.length) batch(() => {
|
|
476
|
+
for (const b of buttons) b.click();
|
|
477
|
+
});
|
|
478
|
+
return buttons.length;
|
|
479
|
+
};
|
|
480
|
+
const rows = [...list.querySelectorAll(":scope > li")].filter(differs);
|
|
481
|
+
if (!rows.length) return 0;
|
|
482
|
+
const root = scroller(list);
|
|
483
|
+
const view = () => root ? root.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
|
|
484
|
+
const height = view().bottom - view().top;
|
|
485
|
+
const { now, later } = planRows(rows.map((li) => li.getBoundingClientRect()), view(), open ? height : 0);
|
|
486
|
+
let stopped = false, handle = 0;
|
|
177
487
|
if (open) {
|
|
178
|
-
|
|
179
|
-
|
|
488
|
+
if (typeof IntersectionObserver === "undefined") return click(rows);
|
|
489
|
+
const near = (li) => planRows([li.getBoundingClientRect()], view(), height).now.length > 0;
|
|
490
|
+
const queue = new Set(now.map((i) => rows[i]));
|
|
491
|
+
let changed2 = 0;
|
|
492
|
+
const flush = () => {
|
|
493
|
+
handle = 0;
|
|
494
|
+
if (stopped) return;
|
|
495
|
+
const next = [];
|
|
496
|
+
for (const li of queue) {
|
|
497
|
+
if (next.length === PER_FRAME) break;
|
|
498
|
+
queue.delete(li);
|
|
499
|
+
if (near(li)) next.push(li);
|
|
500
|
+
else observer.observe(li);
|
|
501
|
+
}
|
|
502
|
+
changed2 += click(next);
|
|
503
|
+
if (queue.size) handle = frame(flush);
|
|
504
|
+
};
|
|
505
|
+
const observer = new IntersectionObserver((entries) => {
|
|
506
|
+
for (const entry of entries) if (entry.isIntersecting) {
|
|
507
|
+
observer.unobserve(entry.target);
|
|
508
|
+
queue.add(entry.target);
|
|
509
|
+
}
|
|
510
|
+
if (queue.size && !handle && !stopped) handle = frame(flush);
|
|
511
|
+
}, { root, rootMargin: `${Math.round(height)}px 0px` });
|
|
512
|
+
later.forEach((i) => observer.observe(rows[i]));
|
|
513
|
+
jobs.set(list, () => {
|
|
514
|
+
stopped = true;
|
|
515
|
+
observer.disconnect();
|
|
180
516
|
});
|
|
181
|
-
|
|
517
|
+
flush();
|
|
518
|
+
return changed2;
|
|
182
519
|
}
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
520
|
+
const changed = click(now.map((i) => rows[i]));
|
|
521
|
+
if (!later.length) return changed;
|
|
522
|
+
const pending = later.map((i) => rows[i]);
|
|
523
|
+
const slice = (deadline) => {
|
|
524
|
+
if (stopped) return;
|
|
525
|
+
click(pending.splice(0, deadline.timeRemaining() > 10 ? PER_FRAME : 1));
|
|
526
|
+
if (pending.length) idle(slice);
|
|
527
|
+
else jobs.delete(list);
|
|
528
|
+
};
|
|
529
|
+
idle(slice);
|
|
530
|
+
jobs.set(list, () => {
|
|
531
|
+
stopped = true;
|
|
532
|
+
});
|
|
533
|
+
return changed;
|
|
194
534
|
}
|
|
195
535
|
function isNativeAddButton(button, zone) {
|
|
196
|
-
if (!button || button.getAttribute("aria-expanded") || button.closest('ol[aria-describedby] > li, [role="dialog"], [data-testid^="open-gallery-"], [data-testid^="block-"], [data-testid^="page-preview"], [data-testid^="bp-"]')) return false;
|
|
536
|
+
if (!button || button.getAttribute("aria-expanded") || button.closest('ol[aria-describedby] > li, [role="dialog"], [data-testid^="open-gallery-"], [data-testid^="block-"], [data-testid^="page-preview"], [data-testid^="bp-"], [data-testid^="zone-"], [data-blockscene-row-actions]')) return false;
|
|
197
537
|
const text = (button.textContent || "").trim();
|
|
198
538
|
return Boolean(text) && new RegExp(`(^|\\s)${String(zone.name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`).test(text);
|
|
199
539
|
}
|
|
@@ -237,7 +577,7 @@ function Wireframe({ template, palette, className, noPreview }) {
|
|
|
237
577
|
}
|
|
238
578
|
|
|
239
579
|
// admin/RowPreviews.tsx
|
|
240
|
-
var
|
|
580
|
+
var React2 = __toESM(require("react"));
|
|
241
581
|
var import_react_dom = require("react-dom");
|
|
242
582
|
|
|
243
583
|
// admin/messages.ts
|
|
@@ -285,10 +625,11 @@ var en_default = {
|
|
|
285
625
|
"templates.faq": "FAQ",
|
|
286
626
|
brokenMedia: "The selected media no longer exists; the next source is used.",
|
|
287
627
|
editor: "Editor preferences",
|
|
288
|
-
enabled: "
|
|
289
|
-
enabledHelp: "Off
|
|
628
|
+
enabled: "Blockscene enabled",
|
|
629
|
+
enabledHelp: "Off turns the whole plugin off at once, with no restart: every edit view is native again and the layout group publish check stops. Use it if something goes wrong in production.",
|
|
290
630
|
showOpenAll: 'Show "Open all blocks"',
|
|
291
631
|
showCloseAll: 'Show "Close all blocks"',
|
|
632
|
+
showRowThumbnails: "Show block thumbnails in the rows",
|
|
292
633
|
initialState: "Initial accordion state",
|
|
293
634
|
"states.closed": "All closed",
|
|
294
635
|
"states.open": "All open",
|
|
@@ -300,13 +641,20 @@ var en_default = {
|
|
|
300
641
|
"modes.form": "Fields",
|
|
301
642
|
"modes.split": "Fields + page",
|
|
302
643
|
"modes.preview": "Visual editor",
|
|
303
|
-
previewModeHelp: "
|
|
644
|
+
previewModeHelp: "Every edit view opens in this mode, unless its content type sets its own below. Editors can switch while they edit; the switch is not remembered.",
|
|
645
|
+
lazyEdit: "Click to edit",
|
|
646
|
+
lazyEditors: "Load rich-text editors on demand",
|
|
647
|
+
lazyFields: "Custom fields loaded on demand",
|
|
648
|
+
lazyEditorsHelp: "Listed custom fields show a read-only preview until clicked or focused, so opening large pages stays fast. Separate uids with commas.",
|
|
649
|
+
lazyFieldsInvalid: "Use up to {max} custom field uids such as plugin::ckeditor5.CKEditor or global::my-field.",
|
|
304
650
|
previewV4: "The whole-page preview is available in the Strapi 5 distribution only; these options have no effect on Strapi 4.",
|
|
305
651
|
modeForm: "Fields",
|
|
306
652
|
modeSplit: "Fields + page",
|
|
307
653
|
modePreview: "Visual editor",
|
|
308
654
|
previewPane: "Page preview",
|
|
309
655
|
resize: "Resize preview pane",
|
|
656
|
+
resizeHint: "Drag to resize; double-click to reset to half",
|
|
657
|
+
scrollToHovered: "Scroll to the highlighted block",
|
|
310
658
|
previewHelp: "Unsaved changes appear in the preview. Click a block to open its form, an image to open the Media Library, a text to edit it.",
|
|
311
659
|
previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
|
|
312
660
|
previewFailed: "The preview did not answer within 15 s. If the frontend is still loading it will appear by itself; the form stays usable.",
|
|
@@ -343,19 +691,137 @@ var en_default = {
|
|
|
343
691
|
diagInsertClose: 'Insert the missing "{expected}" after row {n}',
|
|
344
692
|
diagStrayHint: "Remove the stray marker with the row's own delete action, or move it after an open marker.",
|
|
345
693
|
modeGroup: "Editing mode",
|
|
694
|
+
undo: "Undo",
|
|
695
|
+
redo: "Redo",
|
|
696
|
+
historyGroup: "Undo history",
|
|
346
697
|
saveDisabledHint: "No unsaved changes to save.",
|
|
347
698
|
publishDisabledHint: "Publishing is unavailable: save first, fix the errors shown in the form, or check your permissions.",
|
|
348
699
|
countAll: "{count} blocks",
|
|
349
700
|
countFiltered: "{shown} of {total}",
|
|
350
|
-
filterCategory: "Filter by category",
|
|
351
|
-
allCategories: "All categories",
|
|
352
701
|
showFields: "Fields",
|
|
353
702
|
showFieldsHint: "Show the field list on each block",
|
|
354
703
|
columns: "Columns",
|
|
355
704
|
noPreview: "no preview",
|
|
356
705
|
"templates.none": "No preview",
|
|
357
706
|
noChanges: "No unsaved changes",
|
|
358
|
-
rowPreview: "Open the {label} preview"
|
|
707
|
+
rowPreview: "Open the {label} preview",
|
|
708
|
+
deviceGroup: "Preview width",
|
|
709
|
+
"device.fit": "Fit",
|
|
710
|
+
"device.mobile": "Mobile",
|
|
711
|
+
"device.tablet": "Tablet",
|
|
712
|
+
"device.desktop": "Desktop",
|
|
713
|
+
contentTypes: "Content types",
|
|
714
|
+
contentTypesHelp: 'The gallery, accordions and page preview work on these content types (the ones with a Dynamic Zone). Turn one off to leave its edit view native. "Opens in" is how every edit view of that type starts; editors can still switch while they edit.',
|
|
715
|
+
typeMode: "Opens in",
|
|
716
|
+
modeDefault: "Default ({mode})",
|
|
717
|
+
blockModalDone: "Done",
|
|
718
|
+
crashed: "Blockscene stopped here after an error. The native editor is unaffected. If it happens again, turn Blockscene off in Settings, Blockscene.",
|
|
719
|
+
sidebarLabel: "Page fields",
|
|
720
|
+
"nav.all": "All",
|
|
721
|
+
"nav.recent": "Recently used",
|
|
722
|
+
"nav.starred": "Starred",
|
|
723
|
+
typologiesTitle: "Typologies",
|
|
724
|
+
collapseSidebar: "Collapse sidebar",
|
|
725
|
+
expandSidebar: "Expand sidebar",
|
|
726
|
+
"filters.tags": "Tags",
|
|
727
|
+
"filters.media": "Media",
|
|
728
|
+
"filters.content": "Content",
|
|
729
|
+
clearAll: "Clear all",
|
|
730
|
+
removeFilter: "Remove filter {name}",
|
|
731
|
+
"typologies.hero": "Hero",
|
|
732
|
+
"typologies.text": "Text",
|
|
733
|
+
"typologies.media": "Media",
|
|
734
|
+
"typologies.listing": "Listing",
|
|
735
|
+
"typologies.cards": "Cards",
|
|
736
|
+
"typologies.cta": "Call to action",
|
|
737
|
+
"typologies.form": "Form",
|
|
738
|
+
"typologies.layout": "Layout",
|
|
739
|
+
"facets.image": "Image",
|
|
740
|
+
"facets.video": "Video",
|
|
741
|
+
"facets.gallery": "Gallery",
|
|
742
|
+
"facets.richtext": "Rich text",
|
|
743
|
+
"facets.list": "List",
|
|
744
|
+
"facets.dynamic": "Dynamic",
|
|
745
|
+
"facets.form": "Form",
|
|
746
|
+
star: "Star",
|
|
747
|
+
unstar: "Remove star",
|
|
748
|
+
quickInsert: "Insert {label}",
|
|
749
|
+
insert: "Insert",
|
|
750
|
+
closeDetail: "Close details",
|
|
751
|
+
typology: "Typology",
|
|
752
|
+
typologyAuto: "Automatic ({name})",
|
|
753
|
+
tags: "Tags",
|
|
754
|
+
tagsHelp: "Comma separated, up to 10 tags of 24 characters. They become a gallery filter.",
|
|
755
|
+
sidebarTitle: "Visual editor sidebar: {name}",
|
|
756
|
+
sidebarHelp: "Buttons on an edge of the visual editor. Each one opens some of the document's own fields in a drawer or a modal.",
|
|
757
|
+
sidebarPosition: "Sidebar position",
|
|
758
|
+
"positions.left": "Left",
|
|
759
|
+
"positions.right": "Right",
|
|
760
|
+
"positions.bottom": "Bottom",
|
|
761
|
+
sidebarItemLabel: "Label",
|
|
762
|
+
sidebarIcon: "Icon",
|
|
763
|
+
noIcon: "No icon",
|
|
764
|
+
"icons.text": "Text",
|
|
765
|
+
"icons.tag": "Tag",
|
|
766
|
+
"icons.seo": "SEO",
|
|
767
|
+
"icons.settings": "Settings",
|
|
768
|
+
"icons.image": "Image",
|
|
769
|
+
"icons.link": "Link",
|
|
770
|
+
"icons.palette": "Palette",
|
|
771
|
+
"icons.list": "List",
|
|
772
|
+
"icons.globe": "Globe",
|
|
773
|
+
"icons.info": "Info",
|
|
774
|
+
sidebarOpens: "Opens as",
|
|
775
|
+
"opens.drawer": "Drawer",
|
|
776
|
+
"opens.modal": "Modal",
|
|
777
|
+
moveUp: "Move up",
|
|
778
|
+
moveDown: "Move down",
|
|
779
|
+
sidebarRemove: "Remove item",
|
|
780
|
+
sidebarFields: "Fields",
|
|
781
|
+
sidebarInvalid: "Give the item a label (up to 40 characters, no < or >) and pick at least one field.",
|
|
782
|
+
sidebarInvalidSave: "Fix the sidebar items marked above before saving.",
|
|
783
|
+
sidebarAdd: "Add item",
|
|
784
|
+
sidebarLimit: "Up to {max} items.",
|
|
785
|
+
restoreProject: "Restore project defaults",
|
|
786
|
+
resetAll: "Reset to defaults",
|
|
787
|
+
restoreProjectConfirm: "Discard every setting saved on this page and go back to the project defaults from the code?",
|
|
788
|
+
resetAllConfirm: "Discard every setting saved on this page and go back to the defaults?",
|
|
789
|
+
restored: "Defaults restored.",
|
|
790
|
+
blockPreview: "Live block preview",
|
|
791
|
+
livePreviewFailed: "Live preview unavailable, showing the image.",
|
|
792
|
+
blockPreviewUrl: "Block preview URL",
|
|
793
|
+
blockPreviewUrlHelp: "Optional. A page of your frontend that renders one block on its own, shown large when a gallery card is clicked, e.g. http://localhost:3026/pt-BR/block-preview/'{name}'/'{variant}'. Placeholders: '{uid}', '{name}' (after the dot), '{category}' (before the dot), '{variant}' (default), '{locale}'. Empty uses the page preview route when there is one, else the image.",
|
|
794
|
+
rowActions: "Actions for {label}",
|
|
795
|
+
selectBlock: "Select {label}",
|
|
796
|
+
hiddenBadge: "Hidden",
|
|
797
|
+
hideBlock: "Hide {label} on the site",
|
|
798
|
+
showBlock: "Show {label} on the site",
|
|
799
|
+
duplicateBlock: "Duplicate {label}",
|
|
800
|
+
copyBlock: "Copy {label}",
|
|
801
|
+
confirmDeleteTitle: "Delete block",
|
|
802
|
+
confirmDelete: "Delete block {name}?",
|
|
803
|
+
confirmDeleteMarker: "This is a group marker: only the marker is removed, not the blocks inside the group, and the group stays unbalanced until it is fixed.",
|
|
804
|
+
delete: "Delete",
|
|
805
|
+
selectMode: "Select blocks to copy",
|
|
806
|
+
copySelected: "Copy selected ({count})",
|
|
807
|
+
paste: "Paste {count, plural, one {# block} other {# blocks}}",
|
|
808
|
+
pasted: "{count, plural, one {# block pasted} other {# blocks pasted}}.",
|
|
809
|
+
copied: "{count, plural, one {# block copied} other {# blocks copied}}. Paste on any page of this site.",
|
|
810
|
+
copyFailed: "Could not copy: the browser storage is full or blocked.",
|
|
811
|
+
pasteNotAllowed: 'Nothing was pasted: "{uid}" is not allowed in this zone.',
|
|
812
|
+
pasteFull: "Nothing was pasted: the zone has no room for {count} more blocks.",
|
|
813
|
+
pasteUnbalanced: "Nothing was pasted: the copied blocks contain an incomplete group.",
|
|
814
|
+
rowActionFailed: "The action could not be completed; the form was not changed.",
|
|
815
|
+
rowActionsTitle: "Row actions",
|
|
816
|
+
confirmDeleteOption: "Confirm before deleting a block",
|
|
817
|
+
duplicateOption: 'Show "Duplicate" on each block',
|
|
818
|
+
clipboardOption: 'Show "Copy" and "Paste" (across pages)',
|
|
819
|
+
hiddenBlocks: "Blocks hidden on the site",
|
|
820
|
+
"hiddenModes.strip": "Removed from the content API",
|
|
821
|
+
"hiddenModes.flag": "Sent with the flag (the frontend decides)",
|
|
822
|
+
"hiddenModes.off": "Off (no hide button)",
|
|
823
|
+
hiddenBlocksHelp: "The eye on each block marks it hidden on the site. Removed: content API reads (REST, GraphQL) leave it out, the admin always shows it. Flag: it is sent with the attribute so the frontend can decide.",
|
|
824
|
+
hiddenAttributeOff: "The plugin config sets hiddenAttribute to false: blocks cannot be hidden."
|
|
359
825
|
};
|
|
360
826
|
|
|
361
827
|
// admin/translations/pt-BR.json
|
|
@@ -400,10 +866,11 @@ var pt_BR_default = {
|
|
|
400
866
|
"templates.faq": "FAQ",
|
|
401
867
|
brokenMedia: "A m\xEDdia escolhida n\xE3o existe mais; a pr\xF3xima origem \xE9 usada.",
|
|
402
868
|
editor: "Prefer\xEAncias do editor",
|
|
403
|
-
enabled: "
|
|
404
|
-
enabledHelp: "Desligado
|
|
869
|
+
enabled: "Blockscene ligado",
|
|
870
|
+
enabledHelp: "Desligado, o plugin inteiro para na hora, sem restart: toda tela de edi\xE7\xE3o volta a ser nativa e a verifica\xE7\xE3o de grupos na publica\xE7\xE3o para. Use se algo der errado em produ\xE7\xE3o.",
|
|
405
871
|
showOpenAll: 'Mostrar "Abrir todos os blocos"',
|
|
406
872
|
showCloseAll: 'Mostrar "Fechar todos os blocos"',
|
|
873
|
+
showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
|
|
407
874
|
initialState: "Estado inicial dos accordions",
|
|
408
875
|
"states.closed": "Todos fechados",
|
|
409
876
|
"states.open": "Todos abertos",
|
|
@@ -415,13 +882,20 @@ var pt_BR_default = {
|
|
|
415
882
|
"modes.form": "Campos",
|
|
416
883
|
"modes.split": "Campos + p\xE1gina",
|
|
417
884
|
"modes.preview": "Editor visual",
|
|
418
|
-
previewModeHelp: "
|
|
885
|
+
previewModeHelp: "Toda tela de edi\xE7\xE3o abre neste modo, a menos que o tipo de conte\xFAdo defina o seu abaixo. Quem edita pode trocar durante a edi\xE7\xE3o; a troca n\xE3o fica gravada.",
|
|
886
|
+
lazyEdit: "Clique para editar",
|
|
887
|
+
lazyEditors: "Carregar editores de texto rico sob demanda",
|
|
888
|
+
lazyFields: "Campos personalizados carregados sob demanda",
|
|
889
|
+
lazyEditorsHelp: "Os campos personalizados listados mostram uma pr\xE9via somente leitura at\xE9 receberem clique ou foco, para que p\xE1ginas grandes abram r\xE1pido. Separe os uids com v\xEDrgulas.",
|
|
890
|
+
lazyFieldsInvalid: "Use at\xE9 {max} uids de campos personalizados, como plugin::ckeditor5.CKEditor ou global::meu-campo.",
|
|
419
891
|
previewV4: "A preview de p\xE1gina inteira existe apenas na distribui\xE7\xE3o Strapi 5; estas op\xE7\xF5es n\xE3o t\xEAm efeito no Strapi 4.",
|
|
420
892
|
modeForm: "Campos",
|
|
421
893
|
modeSplit: "Campos + p\xE1gina",
|
|
422
894
|
modePreview: "Editor visual",
|
|
423
895
|
previewPane: "Preview da p\xE1gina",
|
|
424
896
|
resize: "Redimensionar painel de preview",
|
|
897
|
+
resizeHint: "Arraste para redimensionar; clique duplo volta \xE0 metade",
|
|
898
|
+
scrollToHovered: "Rolar at\xE9 o bloco destacado",
|
|
425
899
|
previewHelp: "Altera\xE7\xF5es n\xE3o salvas aparecem na preview. Clique em um bloco para abrir seu formul\xE1rio, em uma imagem para abrir a Media Library, em um texto para edit\xE1-lo.",
|
|
426
900
|
previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
|
|
427
901
|
previewFailed: "A preview n\xE3o respondeu em 15 s. Se o frontend ainda estiver carregando, ela aparece sozinha; o formul\xE1rio continua utiliz\xE1vel.",
|
|
@@ -458,19 +932,137 @@ var pt_BR_default = {
|
|
|
458
932
|
diagInsertClose: 'Inserir o fechamento "{expected}" que falta depois da linha {n}',
|
|
459
933
|
diagStrayHint: "Remova o marcador \xF3rf\xE3o pela a\xE7\xE3o de excluir da pr\xF3pria linha, ou mova-o para depois de uma abertura.",
|
|
460
934
|
modeGroup: "Modo de edi\xE7\xE3o",
|
|
935
|
+
undo: "Desfazer",
|
|
936
|
+
redo: "Refazer",
|
|
937
|
+
historyGroup: "Hist\xF3rico de edi\xE7\xE3o",
|
|
461
938
|
saveDisabledHint: "N\xE3o h\xE1 altera\xE7\xF5es para salvar.",
|
|
462
939
|
publishDisabledHint: "Publica\xE7\xE3o indispon\xEDvel: salve antes, corrija os erros do formul\xE1rio ou verifique suas permiss\xF5es.",
|
|
463
940
|
countAll: "{count} blocos",
|
|
464
941
|
countFiltered: "{shown} de {total}",
|
|
465
|
-
filterCategory: "Filtrar por categoria",
|
|
466
|
-
allCategories: "Todas as categorias",
|
|
467
942
|
showFields: "Campos",
|
|
468
943
|
showFieldsHint: "Mostrar a lista de campos em cada bloco",
|
|
469
944
|
columns: "Colunas",
|
|
470
945
|
noPreview: "sem preview",
|
|
471
946
|
"templates.none": "Sem preview",
|
|
472
947
|
noChanges: "Sem altera\xE7\xF5es pendentes",
|
|
473
|
-
rowPreview: "Abrir a pr\xE9via de {label}"
|
|
948
|
+
rowPreview: "Abrir a pr\xE9via de {label}",
|
|
949
|
+
deviceGroup: "Largura do preview",
|
|
950
|
+
"device.fit": "Ajustar",
|
|
951
|
+
"device.mobile": "Celular",
|
|
952
|
+
"device.tablet": "Tablet",
|
|
953
|
+
"device.desktop": "Desktop",
|
|
954
|
+
contentTypes: "Tipos de conte\xFAdo",
|
|
955
|
+
contentTypesHelp: 'A galeria, os accordions e o preview da p\xE1gina funcionam nestes tipos de conte\xFAdo (os que t\xEAm uma zona din\xE2mica). Desligue um para deixar a edi\xE7\xE3o dele nativa. "Abre em" \xE9 como toda tela de edi\xE7\xE3o desse tipo come\xE7a; quem edita ainda pode trocar durante a edi\xE7\xE3o.',
|
|
956
|
+
typeMode: "Abre em",
|
|
957
|
+
modeDefault: "Padr\xE3o ({mode})",
|
|
958
|
+
blockModalDone: "Concluir",
|
|
959
|
+
crashed: "O Blockscene parou aqui por causa de um erro. O editor nativo n\xE3o foi afetado. Se acontecer de novo, desligue o Blockscene em Settings, Blockscene.",
|
|
960
|
+
sidebarLabel: "Campos da p\xE1gina",
|
|
961
|
+
"nav.all": "Todos",
|
|
962
|
+
"nav.recent": "Usados recentemente",
|
|
963
|
+
"nav.starred": "Favoritos",
|
|
964
|
+
typologiesTitle: "Tipologias",
|
|
965
|
+
collapseSidebar: "Recolher barra lateral",
|
|
966
|
+
expandSidebar: "Expandir barra lateral",
|
|
967
|
+
"filters.tags": "Tags",
|
|
968
|
+
"filters.media": "M\xEDdia",
|
|
969
|
+
"filters.content": "Conte\xFAdo",
|
|
970
|
+
clearAll: "Limpar tudo",
|
|
971
|
+
removeFilter: "Remover filtro {name}",
|
|
972
|
+
"typologies.hero": "Hero",
|
|
973
|
+
"typologies.text": "Texto",
|
|
974
|
+
"typologies.media": "M\xEDdia",
|
|
975
|
+
"typologies.listing": "Listagem",
|
|
976
|
+
"typologies.cards": "Cards",
|
|
977
|
+
"typologies.cta": "Chamada para a\xE7\xE3o",
|
|
978
|
+
"typologies.form": "Formul\xE1rio",
|
|
979
|
+
"typologies.layout": "Layout",
|
|
980
|
+
"facets.image": "Imagem",
|
|
981
|
+
"facets.video": "V\xEDdeo",
|
|
982
|
+
"facets.gallery": "Galeria",
|
|
983
|
+
"facets.richtext": "Texto rico",
|
|
984
|
+
"facets.list": "Lista",
|
|
985
|
+
"facets.dynamic": "Din\xE2mico",
|
|
986
|
+
"facets.form": "Formul\xE1rio",
|
|
987
|
+
star: "Favoritar",
|
|
988
|
+
unstar: "Remover dos favoritos",
|
|
989
|
+
quickInsert: "Inserir {label}",
|
|
990
|
+
insert: "Inserir",
|
|
991
|
+
closeDetail: "Fechar detalhes",
|
|
992
|
+
typology: "Tipologia",
|
|
993
|
+
typologyAuto: "Autom\xE1tica ({name})",
|
|
994
|
+
tags: "Tags",
|
|
995
|
+
tagsHelp: "Separadas por v\xEDrgula, at\xE9 10 tags de 24 caracteres. Viram filtro na galeria.",
|
|
996
|
+
sidebarTitle: "Barra lateral do editor visual: {name}",
|
|
997
|
+
sidebarHelp: "Bot\xF5es numa borda do editor visual. Cada um abre alguns campos do pr\xF3prio documento numa gaveta ou num modal.",
|
|
998
|
+
sidebarPosition: "Posi\xE7\xE3o da barra lateral",
|
|
999
|
+
"positions.left": "Esquerda",
|
|
1000
|
+
"positions.right": "Direita",
|
|
1001
|
+
"positions.bottom": "Embaixo",
|
|
1002
|
+
sidebarItemLabel: "R\xF3tulo",
|
|
1003
|
+
sidebarIcon: "\xCDcone",
|
|
1004
|
+
noIcon: "Sem \xEDcone",
|
|
1005
|
+
"icons.text": "Texto",
|
|
1006
|
+
"icons.tag": "Etiqueta",
|
|
1007
|
+
"icons.seo": "SEO",
|
|
1008
|
+
"icons.settings": "Configura\xE7\xF5es",
|
|
1009
|
+
"icons.image": "Imagem",
|
|
1010
|
+
"icons.link": "Link",
|
|
1011
|
+
"icons.palette": "Paleta",
|
|
1012
|
+
"icons.list": "Lista",
|
|
1013
|
+
"icons.globe": "Globo",
|
|
1014
|
+
"icons.info": "Informa\xE7\xE3o",
|
|
1015
|
+
sidebarOpens: "Abre como",
|
|
1016
|
+
"opens.drawer": "Gaveta",
|
|
1017
|
+
"opens.modal": "Modal",
|
|
1018
|
+
moveUp: "Mover para cima",
|
|
1019
|
+
moveDown: "Mover para baixo",
|
|
1020
|
+
sidebarRemove: "Remover item",
|
|
1021
|
+
sidebarFields: "Campos",
|
|
1022
|
+
sidebarInvalid: "D\xEA um r\xF3tulo ao item (at\xE9 40 caracteres, sem < ou >) e escolha pelo menos um campo.",
|
|
1023
|
+
sidebarInvalidSave: "Corrija os itens da barra lateral marcados acima antes de salvar.",
|
|
1024
|
+
sidebarAdd: "Adicionar item",
|
|
1025
|
+
sidebarLimit: "At\xE9 {max} itens.",
|
|
1026
|
+
restoreProject: "Restaurar padr\xF5es do projeto",
|
|
1027
|
+
resetAll: "Restaurar padr\xF5es",
|
|
1028
|
+
restoreProjectConfirm: "Descartar todas as configura\xE7\xF5es salvas nesta p\xE1gina e voltar aos padr\xF5es do projeto definidos no c\xF3digo?",
|
|
1029
|
+
resetAllConfirm: "Descartar todas as configura\xE7\xF5es salvas nesta p\xE1gina e voltar aos padr\xF5es?",
|
|
1030
|
+
restored: "Padr\xF5es restaurados.",
|
|
1031
|
+
blockPreview: "Preview ao vivo do bloco",
|
|
1032
|
+
livePreviewFailed: "Preview ao vivo indispon\xEDvel, mostrando a imagem.",
|
|
1033
|
+
blockPreviewUrl: "URL de preview do bloco",
|
|
1034
|
+
blockPreviewUrlHelp: "Opcional. Uma p\xE1gina do seu frontend que renderiza um bloco sozinho, mostrada em tamanho grande ao clicar num card da galeria, por exemplo http://localhost:3026/pt-BR/block-preview/'{name}'/'{variant}'. Marcadores: '{uid}', '{name}' (depois do ponto), '{category}' (antes do ponto), '{variant}' (default), '{locale}'. Vazio usa a rota de preview de p\xE1gina quando existir, sen\xE3o a imagem.",
|
|
1035
|
+
rowActions: "A\xE7\xF5es de {label}",
|
|
1036
|
+
selectBlock: "Selecionar {label}",
|
|
1037
|
+
hiddenBadge: "Oculto",
|
|
1038
|
+
hideBlock: "Ocultar {label} no site",
|
|
1039
|
+
showBlock: "Mostrar {label} no site",
|
|
1040
|
+
duplicateBlock: "Duplicar {label}",
|
|
1041
|
+
copyBlock: "Copiar {label}",
|
|
1042
|
+
confirmDeleteTitle: "Excluir bloco",
|
|
1043
|
+
confirmDelete: "Excluir o bloco {name}?",
|
|
1044
|
+
confirmDeleteMarker: "Este \xE9 um marcador de grupo: s\xF3 o marcador \xE9 removido, n\xE3o os blocos dentro do grupo, e o grupo fica desbalanceado at\xE9 ser corrigido.",
|
|
1045
|
+
delete: "Excluir",
|
|
1046
|
+
selectMode: "Selecionar blocos para copiar",
|
|
1047
|
+
copySelected: "Copiar selecionados ({count})",
|
|
1048
|
+
paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
|
|
1049
|
+
pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
|
|
1050
|
+
copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
|
|
1051
|
+
copyFailed: "N\xE3o foi poss\xEDvel copiar: o armazenamento do navegador est\xE1 cheio ou bloqueado.",
|
|
1052
|
+
pasteNotAllowed: 'Nada foi colado: "{uid}" n\xE3o \xE9 permitido nesta zona.',
|
|
1053
|
+
pasteFull: "Nada foi colado: a zona n\xE3o tem espa\xE7o para mais {count} blocos.",
|
|
1054
|
+
pasteUnbalanced: "Nada foi colado: os blocos copiados cont\xEAm um grupo incompleto.",
|
|
1055
|
+
rowActionFailed: "A a\xE7\xE3o n\xE3o p\xF4de ser conclu\xEDda; o formul\xE1rio n\xE3o foi alterado.",
|
|
1056
|
+
rowActionsTitle: "A\xE7\xF5es dos blocos",
|
|
1057
|
+
confirmDeleteOption: "Confirmar antes de excluir um bloco",
|
|
1058
|
+
duplicateOption: 'Mostrar "Duplicar" em cada bloco',
|
|
1059
|
+
clipboardOption: 'Mostrar "Copiar" e "Colar" (entre p\xE1ginas)',
|
|
1060
|
+
hiddenBlocks: "Blocos ocultos no site",
|
|
1061
|
+
"hiddenModes.strip": "Removidos da API de conte\xFAdo",
|
|
1062
|
+
"hiddenModes.flag": "Enviados com a marca\xE7\xE3o (o frontend decide)",
|
|
1063
|
+
"hiddenModes.off": "Desligado (sem bot\xE3o de ocultar)",
|
|
1064
|
+
hiddenBlocksHelp: "O olho em cada bloco o marca como oculto no site. Removidos: as leituras da API de conte\xFAdo (REST, GraphQL) o deixam de fora; o admin sempre o mostra. Marca\xE7\xE3o: ele \xE9 enviado com o atributo para o frontend decidir.",
|
|
1065
|
+
hiddenAttributeOff: "A config do plugin define hiddenAttribute como false: n\xE3o \xE9 poss\xEDvel ocultar blocos."
|
|
474
1066
|
};
|
|
475
1067
|
|
|
476
1068
|
// admin/translations/pt.json
|
|
@@ -515,10 +1107,11 @@ var pt_default = {
|
|
|
515
1107
|
"templates.faq": "FAQ",
|
|
516
1108
|
brokenMedia: "A m\xEDdia escolhida n\xE3o existe mais; a pr\xF3xima origem \xE9 usada.",
|
|
517
1109
|
editor: "Prefer\xEAncias do editor",
|
|
518
|
-
enabled: "
|
|
519
|
-
enabledHelp: "Desligado
|
|
1110
|
+
enabled: "Blockscene ligado",
|
|
1111
|
+
enabledHelp: "Desligado, o plugin inteiro para de imediato, sem rein\xEDcio: todos os ecr\xE3s de edi\xE7\xE3o voltam a ser nativos e a verifica\xE7\xE3o de grupos na publica\xE7\xE3o para. Use-o se algo correr mal em produ\xE7\xE3o.",
|
|
520
1112
|
showOpenAll: 'Mostrar "Abrir todos os blocos"',
|
|
521
1113
|
showCloseAll: 'Mostrar "Fechar todos os blocos"',
|
|
1114
|
+
showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
|
|
522
1115
|
initialState: "Estado inicial dos accordions",
|
|
523
1116
|
"states.closed": "Todos fechados",
|
|
524
1117
|
"states.open": "Todos abertos",
|
|
@@ -530,13 +1123,20 @@ var pt_default = {
|
|
|
530
1123
|
"modes.form": "Campos",
|
|
531
1124
|
"modes.split": "Campos + p\xE1gina",
|
|
532
1125
|
"modes.preview": "Editor visual",
|
|
533
|
-
previewModeHelp: "
|
|
1126
|
+
previewModeHelp: "Cada ecr\xE3 de edi\xE7\xE3o abre neste modo, salvo se o tipo de conte\xFAdo definir o seu abaixo. Quem edita pode mudar durante a edi\xE7\xE3o; a mudan\xE7a n\xE3o fica guardada.",
|
|
1127
|
+
lazyEdit: "Clique para editar",
|
|
1128
|
+
lazyEditors: "Carregar editores de texto rico a pedido",
|
|
1129
|
+
lazyFields: "Campos personalizados carregados a pedido",
|
|
1130
|
+
lazyEditorsHelp: "Os campos personalizados indicados mostram uma pr\xE9-visualiza\xE7\xE3o s\xF3 de leitura at\xE9 receberem clique ou foco, para que p\xE1ginas grandes abram depressa. Separe os uids com v\xEDrgulas.",
|
|
1131
|
+
lazyFieldsInvalid: "Use at\xE9 {max} uids de campos personalizados, como plugin::ckeditor5.CKEditor ou global::meu-campo.",
|
|
534
1132
|
previewV4: "A pr\xE9-visualiza\xE7\xE3o de p\xE1gina inteira existe apenas na distribui\xE7\xE3o Strapi 5; estas op\xE7\xF5es n\xE3o t\xEAm efeito no Strapi 4.",
|
|
535
1133
|
modeForm: "Campos",
|
|
536
1134
|
modeSplit: "Campos + p\xE1gina",
|
|
537
1135
|
modePreview: "Editor visual",
|
|
538
1136
|
previewPane: "Pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
|
|
539
1137
|
resize: "Redimensionar painel de pr\xE9-visualiza\xE7\xE3o",
|
|
1138
|
+
resizeHint: "Arraste para redimensionar; duplo clique rep\xF5e a metade",
|
|
1139
|
+
scrollToHovered: "Deslocar at\xE9 ao bloco destacado",
|
|
540
1140
|
previewHelp: "As altera\xE7\xF5es por guardar aparecem na pr\xE9-visualiza\xE7\xE3o. Clique num bloco para abrir o seu formul\xE1rio, numa imagem para abrir a Media Library, num texto para o editar.",
|
|
541
1141
|
previewNoUrl: "Sem URL de pr\xE9-visualiza\xE7\xE3o: defina em Defini\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
|
|
542
1142
|
previewFailed: "A pr\xE9-visualiza\xE7\xE3o n\xE3o respondeu em 15 s. Se o frontend ainda estiver a carregar, ela aparece sozinha; o formul\xE1rio continua utiliz\xE1vel.",
|
|
@@ -573,19 +1173,137 @@ var pt_default = {
|
|
|
573
1173
|
diagInsertClose: 'Inserir o fecho "{expected}" em falta depois da linha {n}',
|
|
574
1174
|
diagStrayHint: "Remova o marcador \xF3rf\xE3o pela a\xE7\xE3o de eliminar da pr\xF3pria linha, ou mova-o para depois de uma abertura.",
|
|
575
1175
|
modeGroup: "Modo de edi\xE7\xE3o",
|
|
1176
|
+
undo: "Anular",
|
|
1177
|
+
redo: "Refazer",
|
|
1178
|
+
historyGroup: "Hist\xF3rico de edi\xE7\xE3o",
|
|
576
1179
|
saveDisabledHint: "N\xE3o h\xE1 altera\xE7\xF5es por guardar.",
|
|
577
1180
|
publishDisabledHint: "Publica\xE7\xE3o indispon\xEDvel: guarde antes, corrija os erros do formul\xE1rio ou verifique as suas permiss\xF5es.",
|
|
578
1181
|
countAll: "{count} blocos",
|
|
579
1182
|
countFiltered: "{shown} de {total}",
|
|
580
|
-
filterCategory: "Filtrar por categoria",
|
|
581
|
-
allCategories: "Todas as categorias",
|
|
582
1183
|
showFields: "Campos",
|
|
583
1184
|
showFieldsHint: "Mostrar a lista de campos em cada bloco",
|
|
584
1185
|
columns: "Colunas",
|
|
585
1186
|
noPreview: "sem pr\xE9-visualiza\xE7\xE3o",
|
|
586
1187
|
"templates.none": "Sem pr\xE9-visualiza\xE7\xE3o",
|
|
587
1188
|
noChanges: "Sem altera\xE7\xF5es pendentes",
|
|
588
|
-
rowPreview: "Abrir a pr\xE9-visualiza\xE7\xE3o de {label}"
|
|
1189
|
+
rowPreview: "Abrir a pr\xE9-visualiza\xE7\xE3o de {label}",
|
|
1190
|
+
deviceGroup: "Largura da pr\xE9-visualiza\xE7\xE3o",
|
|
1191
|
+
"device.fit": "Ajustar",
|
|
1192
|
+
"device.mobile": "Telem\xF3vel",
|
|
1193
|
+
"device.tablet": "Tablet",
|
|
1194
|
+
"device.desktop": "Computador",
|
|
1195
|
+
contentTypes: "Tipos de conte\xFAdo",
|
|
1196
|
+
contentTypesHelp: 'A galeria, os acorde\xF5es e a pr\xE9-visualiza\xE7\xE3o da p\xE1gina funcionam nestes tipos de conte\xFAdo (os que t\xEAm uma zona din\xE2mica). Desligue um para manter a edi\xE7\xE3o nativa. "Abre em" \xE9 como come\xE7a cada ecr\xE3 de edi\xE7\xE3o desse tipo; quem edita pode sempre mudar durante a edi\xE7\xE3o.',
|
|
1197
|
+
typeMode: "Abre em",
|
|
1198
|
+
modeDefault: "Predefini\xE7\xE3o ({mode})",
|
|
1199
|
+
blockModalDone: "Concluir",
|
|
1200
|
+
crashed: "O Blockscene parou aqui devido a um erro. O editor nativo n\xE3o foi afetado. Se voltar a acontecer, desligue o Blockscene em Settings, Blockscene.",
|
|
1201
|
+
sidebarLabel: "Campos da p\xE1gina",
|
|
1202
|
+
"nav.all": "Todos",
|
|
1203
|
+
"nav.recent": "Usados recentemente",
|
|
1204
|
+
"nav.starred": "Favoritos",
|
|
1205
|
+
typologiesTitle: "Tipologias",
|
|
1206
|
+
collapseSidebar: "Recolher barra lateral",
|
|
1207
|
+
expandSidebar: "Expandir barra lateral",
|
|
1208
|
+
"filters.tags": "Etiquetas",
|
|
1209
|
+
"filters.media": "Multim\xE9dia",
|
|
1210
|
+
"filters.content": "Conte\xFAdo",
|
|
1211
|
+
clearAll: "Limpar tudo",
|
|
1212
|
+
removeFilter: "Remover filtro {name}",
|
|
1213
|
+
"typologies.hero": "Hero",
|
|
1214
|
+
"typologies.text": "Texto",
|
|
1215
|
+
"typologies.media": "Multim\xE9dia",
|
|
1216
|
+
"typologies.listing": "Listagem",
|
|
1217
|
+
"typologies.cards": "Cart\xF5es",
|
|
1218
|
+
"typologies.cta": "Chamada para a\xE7\xE3o",
|
|
1219
|
+
"typologies.form": "Formul\xE1rio",
|
|
1220
|
+
"typologies.layout": "Layout",
|
|
1221
|
+
"facets.image": "Imagem",
|
|
1222
|
+
"facets.video": "V\xEDdeo",
|
|
1223
|
+
"facets.gallery": "Galeria",
|
|
1224
|
+
"facets.richtext": "Texto rico",
|
|
1225
|
+
"facets.list": "Lista",
|
|
1226
|
+
"facets.dynamic": "Din\xE2mico",
|
|
1227
|
+
"facets.form": "Formul\xE1rio",
|
|
1228
|
+
star: "Marcar como favorito",
|
|
1229
|
+
unstar: "Remover dos favoritos",
|
|
1230
|
+
quickInsert: "Inserir {label}",
|
|
1231
|
+
insert: "Inserir",
|
|
1232
|
+
closeDetail: "Fechar detalhes",
|
|
1233
|
+
typology: "Tipologia",
|
|
1234
|
+
typologyAuto: "Autom\xE1tica ({name})",
|
|
1235
|
+
tags: "Etiquetas",
|
|
1236
|
+
tagsHelp: "Separadas por v\xEDrgulas, at\xE9 10 etiquetas de 24 caracteres. Tornam-se um filtro na galeria.",
|
|
1237
|
+
sidebarTitle: "Barra lateral do editor visual: {name}",
|
|
1238
|
+
sidebarHelp: "Bot\xF5es numa margem do editor visual. Cada um abre alguns campos do pr\xF3prio documento numa gaveta ou num modal.",
|
|
1239
|
+
sidebarPosition: "Posi\xE7\xE3o da barra lateral",
|
|
1240
|
+
"positions.left": "Esquerda",
|
|
1241
|
+
"positions.right": "Direita",
|
|
1242
|
+
"positions.bottom": "Em baixo",
|
|
1243
|
+
sidebarItemLabel: "R\xF3tulo",
|
|
1244
|
+
sidebarIcon: "\xCDcone",
|
|
1245
|
+
noIcon: "Sem \xEDcone",
|
|
1246
|
+
"icons.text": "Texto",
|
|
1247
|
+
"icons.tag": "Etiqueta",
|
|
1248
|
+
"icons.seo": "SEO",
|
|
1249
|
+
"icons.settings": "Defini\xE7\xF5es",
|
|
1250
|
+
"icons.image": "Imagem",
|
|
1251
|
+
"icons.link": "Liga\xE7\xE3o",
|
|
1252
|
+
"icons.palette": "Paleta",
|
|
1253
|
+
"icons.list": "Lista",
|
|
1254
|
+
"icons.globe": "Globo",
|
|
1255
|
+
"icons.info": "Informa\xE7\xE3o",
|
|
1256
|
+
sidebarOpens: "Abre como",
|
|
1257
|
+
"opens.drawer": "Gaveta",
|
|
1258
|
+
"opens.modal": "Modal",
|
|
1259
|
+
moveUp: "Mover para cima",
|
|
1260
|
+
moveDown: "Mover para baixo",
|
|
1261
|
+
sidebarRemove: "Remover item",
|
|
1262
|
+
sidebarFields: "Campos",
|
|
1263
|
+
sidebarInvalid: "D\xEA um r\xF3tulo ao item (at\xE9 40 caracteres, sem < ou >) e escolha pelo menos um campo.",
|
|
1264
|
+
sidebarInvalidSave: "Corrija os itens da barra lateral assinalados acima antes de guardar.",
|
|
1265
|
+
sidebarAdd: "Adicionar item",
|
|
1266
|
+
sidebarLimit: "At\xE9 {max} itens.",
|
|
1267
|
+
restoreProject: "Repor predefini\xE7\xF5es do projeto",
|
|
1268
|
+
resetAll: "Repor predefini\xE7\xF5es",
|
|
1269
|
+
restoreProjectConfirm: "Descartar todas as defini\xE7\xF5es guardadas nesta p\xE1gina e voltar \xE0s predefini\xE7\xF5es do projeto definidas no c\xF3digo?",
|
|
1270
|
+
resetAllConfirm: "Descartar todas as defini\xE7\xF5es guardadas nesta p\xE1gina e voltar \xE0s predefini\xE7\xF5es?",
|
|
1271
|
+
restored: "Predefini\xE7\xF5es repostas.",
|
|
1272
|
+
blockPreview: "Pr\xE9-visualiza\xE7\xE3o ao vivo do bloco",
|
|
1273
|
+
livePreviewFailed: "Pr\xE9-visualiza\xE7\xE3o ao vivo indispon\xEDvel, a mostrar a imagem.",
|
|
1274
|
+
blockPreviewUrl: "URL de pr\xE9-visualiza\xE7\xE3o do bloco",
|
|
1275
|
+
blockPreviewUrlHelp: "Opcional. Uma p\xE1gina do seu frontend que renderiza um bloco isolado, mostrada em grande ao clicar num cart\xE3o da galeria, por exemplo http://localhost:3026/pt-PT/block-preview/'{name}'/'{variant}'. Marcadores: '{uid}', '{name}' (depois do ponto), '{category}' (antes do ponto), '{variant}' (default), '{locale}'. Vazio usa a rota de pr\xE9-visualiza\xE7\xE3o de p\xE1gina quando existir, caso contr\xE1rio a imagem.",
|
|
1276
|
+
rowActions: "A\xE7\xF5es de {label}",
|
|
1277
|
+
selectBlock: "Selecionar {label}",
|
|
1278
|
+
hiddenBadge: "Oculto",
|
|
1279
|
+
hideBlock: "Ocultar {label} no site",
|
|
1280
|
+
showBlock: "Mostrar {label} no site",
|
|
1281
|
+
duplicateBlock: "Duplicar {label}",
|
|
1282
|
+
copyBlock: "Copiar {label}",
|
|
1283
|
+
confirmDeleteTitle: "Eliminar bloco",
|
|
1284
|
+
confirmDelete: "Eliminar o bloco {name}?",
|
|
1285
|
+
confirmDeleteMarker: "Este \xE9 um marcador de grupo: s\xF3 o marcador \xE9 removido, n\xE3o os blocos dentro do grupo, e o grupo fica desequilibrado at\xE9 ser corrigido.",
|
|
1286
|
+
delete: "Eliminar",
|
|
1287
|
+
selectMode: "Selecionar blocos para copiar",
|
|
1288
|
+
copySelected: "Copiar selecionados ({count})",
|
|
1289
|
+
paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
|
|
1290
|
+
pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
|
|
1291
|
+
copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
|
|
1292
|
+
copyFailed: "N\xE3o foi poss\xEDvel copiar: o armazenamento do navegador est\xE1 cheio ou bloqueado.",
|
|
1293
|
+
pasteNotAllowed: 'Nada foi colado: "{uid}" n\xE3o \xE9 permitido nesta zona.',
|
|
1294
|
+
pasteFull: "Nada foi colado: a zona n\xE3o tem espa\xE7o para mais {count} blocos.",
|
|
1295
|
+
pasteUnbalanced: "Nada foi colado: os blocos copiados cont\xEAm um grupo incompleto.",
|
|
1296
|
+
rowActionFailed: "N\xE3o foi poss\xEDvel concluir a a\xE7\xE3o; o formul\xE1rio n\xE3o foi alterado.",
|
|
1297
|
+
rowActionsTitle: "A\xE7\xF5es dos blocos",
|
|
1298
|
+
confirmDeleteOption: "Confirmar antes de eliminar um bloco",
|
|
1299
|
+
duplicateOption: 'Mostrar "Duplicar" em cada bloco',
|
|
1300
|
+
clipboardOption: 'Mostrar "Copiar" e "Colar" (entre p\xE1ginas)',
|
|
1301
|
+
hiddenBlocks: "Blocos ocultos no site",
|
|
1302
|
+
"hiddenModes.strip": "Removidos da API de conte\xFAdo",
|
|
1303
|
+
"hiddenModes.flag": "Enviados com a marca\xE7\xE3o (o frontend decide)",
|
|
1304
|
+
"hiddenModes.off": "Desligado (sem bot\xE3o de ocultar)",
|
|
1305
|
+
hiddenBlocksHelp: "O olho em cada bloco marca-o como oculto no site. Removidos: as leituras da API de conte\xFAdo (REST, GraphQL) deixam-no de fora; o admin mostra-o sempre. Marca\xE7\xE3o: \xE9 enviado com o atributo para o frontend decidir.",
|
|
1306
|
+
hiddenAttributeOff: "A configura\xE7\xE3o do plugin define hiddenAttribute como false: n\xE3o \xE9 poss\xEDvel ocultar blocos."
|
|
589
1307
|
};
|
|
590
1308
|
|
|
591
1309
|
// admin/translations/fr.json
|
|
@@ -630,10 +1348,11 @@ var fr_default = {
|
|
|
630
1348
|
"templates.faq": "FAQ",
|
|
631
1349
|
brokenMedia: "Le m\xE9dia choisi n'existe plus ; la source suivante est utilis\xE9e.",
|
|
632
1350
|
editor: "Pr\xE9f\xE9rences de l'\xE9diteur",
|
|
633
|
-
enabled: "
|
|
634
|
-
enabledHelp: "D\xE9sactiv\xE9
|
|
1351
|
+
enabled: "Blockscene activ\xE9",
|
|
1352
|
+
enabledHelp: "D\xE9sactiv\xE9, tout le plugin s'arr\xEAte aussit\xF4t, sans red\xE9marrage : chaque vue d'\xE9dition redevient native et la v\xE9rification des groupes \xE0 la publication s'arr\xEAte. \xC0 utiliser si quelque chose se passe mal en production.",
|
|
635
1353
|
showOpenAll: "Afficher \xAB Ouvrir tous les blocs \xBB",
|
|
636
1354
|
showCloseAll: "Afficher \xAB Fermer tous les blocs \xBB",
|
|
1355
|
+
showRowThumbnails: "Afficher les miniatures des blocs dans les lignes",
|
|
637
1356
|
initialState: "\xC9tat initial des accord\xE9ons",
|
|
638
1357
|
"states.closed": "Tous ferm\xE9s",
|
|
639
1358
|
"states.open": "Tous ouverts",
|
|
@@ -645,13 +1364,20 @@ var fr_default = {
|
|
|
645
1364
|
"modes.form": "Champs",
|
|
646
1365
|
"modes.split": "Champs + page",
|
|
647
1366
|
"modes.preview": "\xC9diteur visuel",
|
|
648
|
-
previewModeHelp: "
|
|
1367
|
+
previewModeHelp: "Chaque vue d'\xE9dition s'ouvre dans ce mode, sauf si son type de contenu d\xE9finit le sien ci-dessous. L'\xE9diteur peut changer pendant l'\xE9dition ; ce choix n'est pas m\xE9moris\xE9.",
|
|
1368
|
+
lazyEdit: "Cliquer pour modifier",
|
|
1369
|
+
lazyEditors: "Charger les \xE9diteurs de texte riche \xE0 la demande",
|
|
1370
|
+
lazyFields: "Champs personnalis\xE9s charg\xE9s \xE0 la demande",
|
|
1371
|
+
lazyEditorsHelp: "Les champs personnalis\xE9s list\xE9s affichent un aper\xE7u en lecture seule jusqu'au clic ou au focus, pour que les grandes pages s'ouvrent vite. S\xE9parez les uids par des virgules.",
|
|
1372
|
+
lazyFieldsInvalid: "Utilisez jusqu'\xE0 {max} uids de champs personnalis\xE9s, comme plugin::ckeditor5.CKEditor ou global::mon-champ.",
|
|
649
1373
|
previewV4: "L'aper\xE7u de page enti\xE8re n'existe que dans la distribution Strapi 5 ; ces options n'ont aucun effet sur Strapi 4.",
|
|
650
1374
|
modeForm: "Champs",
|
|
651
1375
|
modeSplit: "Champs + page",
|
|
652
1376
|
modePreview: "\xC9diteur visuel",
|
|
653
1377
|
previewPane: "Aper\xE7u de la page",
|
|
654
1378
|
resize: "Redimensionner le panneau d'aper\xE7u",
|
|
1379
|
+
resizeHint: "Faites glisser pour redimensionner ; double-clic pour revenir \xE0 la moiti\xE9",
|
|
1380
|
+
scrollToHovered: "Faire d\xE9filer jusqu\u2019au bloc en surbrillance",
|
|
655
1381
|
previewHelp: "Les modifications non enregistr\xE9es apparaissent dans l'aper\xE7u. Cliquez sur un bloc pour ouvrir son formulaire, sur une image pour ouvrir la M\xE9diath\xE8que, sur un texte pour le modifier.",
|
|
656
1382
|
previewNoUrl: "Aucune URL d'aper\xE7u : d\xE9finissez-la dans Param\xE8tres, Blockscene, ou configurez l'aper\xE7u natif de Strapi pour ce type de contenu.",
|
|
657
1383
|
previewFailed: "L'aper\xE7u n'a pas r\xE9pondu en 15 s. Si le frontend est encore en train de charger, il appara\xEEtra de lui-m\xEAme ; le formulaire reste utilisable.",
|
|
@@ -688,19 +1414,137 @@ var fr_default = {
|
|
|
688
1414
|
diagInsertClose: "Ins\xE9rer la fermeture \xAB {expected} \xBB manquante apr\xE8s la ligne {n}",
|
|
689
1415
|
diagStrayHint: "Supprimez le marqueur orphelin avec l'action de suppression de la ligne, ou d\xE9placez-le apr\xE8s une ouverture.",
|
|
690
1416
|
modeGroup: "Mode d'\xE9dition",
|
|
1417
|
+
undo: "Annuler",
|
|
1418
|
+
redo: "R\xE9tablir",
|
|
1419
|
+
historyGroup: "Historique des modifications",
|
|
691
1420
|
saveDisabledHint: "Aucune modification \xE0 enregistrer.",
|
|
692
1421
|
publishDisabledHint: "Publication indisponible : enregistrez d'abord, corrigez les erreurs du formulaire ou v\xE9rifiez vos droits.",
|
|
693
1422
|
countAll: "{count} blocs",
|
|
694
1423
|
countFiltered: "{shown} sur {total}",
|
|
695
|
-
filterCategory: "Filtrer par cat\xE9gorie",
|
|
696
|
-
allCategories: "Toutes les cat\xE9gories",
|
|
697
1424
|
showFields: "Champs",
|
|
698
1425
|
showFieldsHint: "Afficher la liste des champs sur chaque bloc",
|
|
699
1426
|
columns: "Colonnes",
|
|
700
1427
|
noPreview: "pas d\u2019aper\xE7u",
|
|
701
1428
|
"templates.none": "Pas d\u2019aper\xE7u",
|
|
702
1429
|
noChanges: "Aucune modification en attente",
|
|
703
|
-
rowPreview: "Ouvrir l\u2019aper\xE7u de {label}"
|
|
1430
|
+
rowPreview: "Ouvrir l\u2019aper\xE7u de {label}",
|
|
1431
|
+
deviceGroup: "Largeur de l'aper\xE7u",
|
|
1432
|
+
"device.fit": "Ajuster",
|
|
1433
|
+
"device.mobile": "Mobile",
|
|
1434
|
+
"device.tablet": "Tablette",
|
|
1435
|
+
"device.desktop": "Ordinateur",
|
|
1436
|
+
contentTypes: "Types de contenu",
|
|
1437
|
+
contentTypesHelp: "La galerie, les accord\xE9ons et l'aper\xE7u de page fonctionnent sur ces types de contenu (ceux qui ont une Dynamic Zone). D\xE9sactivez-en un pour garder son \xE9dition native. \xAB S'ouvre en \xBB d\xE9finit le mode de d\xE9part de chaque vue d'\xE9dition de ce type ; l'\xE9diteur peut toujours changer pendant l'\xE9dition.",
|
|
1438
|
+
typeMode: "S'ouvre en",
|
|
1439
|
+
modeDefault: "Par d\xE9faut ({mode})",
|
|
1440
|
+
blockModalDone: "Termin\xE9",
|
|
1441
|
+
crashed: "Blockscene s'est arr\xEAt\xE9 ici \xE0 cause d'une erreur. L'\xE9diteur natif n'est pas touch\xE9. Si cela se reproduit, d\xE9sactivez Blockscene dans Settings, Blockscene.",
|
|
1442
|
+
sidebarLabel: "Champs de la page",
|
|
1443
|
+
"nav.all": "Tous",
|
|
1444
|
+
"nav.recent": "Utilis\xE9s r\xE9cemment",
|
|
1445
|
+
"nav.starred": "Favoris",
|
|
1446
|
+
typologiesTitle: "Typologies",
|
|
1447
|
+
collapseSidebar: "R\xE9duire la barre lat\xE9rale",
|
|
1448
|
+
expandSidebar: "D\xE9plier la barre lat\xE9rale",
|
|
1449
|
+
"filters.tags": "\xC9tiquettes",
|
|
1450
|
+
"filters.media": "M\xE9dias",
|
|
1451
|
+
"filters.content": "Contenu",
|
|
1452
|
+
clearAll: "Tout effacer",
|
|
1453
|
+
removeFilter: "Retirer le filtre {name}",
|
|
1454
|
+
"typologies.hero": "Hero",
|
|
1455
|
+
"typologies.text": "Texte",
|
|
1456
|
+
"typologies.media": "M\xE9dias",
|
|
1457
|
+
"typologies.listing": "Liste d'\xE9l\xE9ments",
|
|
1458
|
+
"typologies.cards": "Cartes",
|
|
1459
|
+
"typologies.cta": "Appel \xE0 l'action",
|
|
1460
|
+
"typologies.form": "Formulaire",
|
|
1461
|
+
"typologies.layout": "Mise en page",
|
|
1462
|
+
"facets.image": "Image",
|
|
1463
|
+
"facets.video": "Vid\xE9o",
|
|
1464
|
+
"facets.gallery": "Galerie",
|
|
1465
|
+
"facets.richtext": "Texte riche",
|
|
1466
|
+
"facets.list": "Liste",
|
|
1467
|
+
"facets.dynamic": "Dynamique",
|
|
1468
|
+
"facets.form": "Formulaire",
|
|
1469
|
+
star: "Ajouter aux favoris",
|
|
1470
|
+
unstar: "Retirer des favoris",
|
|
1471
|
+
quickInsert: "Ins\xE9rer {label}",
|
|
1472
|
+
insert: "Ins\xE9rer",
|
|
1473
|
+
closeDetail: "Fermer les d\xE9tails",
|
|
1474
|
+
typology: "Typologie",
|
|
1475
|
+
typologyAuto: "Automatique ({name})",
|
|
1476
|
+
tags: "\xC9tiquettes",
|
|
1477
|
+
tagsHelp: "S\xE9par\xE9es par des virgules, jusqu'\xE0 10 \xE9tiquettes de 24 caract\xE8res. Elles deviennent un filtre de la galerie.",
|
|
1478
|
+
sidebarTitle: "Barre lat\xE9rale de l'\xE9diteur visuel : {name}",
|
|
1479
|
+
sidebarHelp: "Des boutons sur un bord de l'\xE9diteur visuel. Chacun ouvre certains champs du document dans un tiroir ou une fen\xEAtre modale.",
|
|
1480
|
+
sidebarPosition: "Position de la barre lat\xE9rale",
|
|
1481
|
+
"positions.left": "Gauche",
|
|
1482
|
+
"positions.right": "Droite",
|
|
1483
|
+
"positions.bottom": "En bas",
|
|
1484
|
+
sidebarItemLabel: "Libell\xE9",
|
|
1485
|
+
sidebarIcon: "Ic\xF4ne",
|
|
1486
|
+
noIcon: "Aucune ic\xF4ne",
|
|
1487
|
+
"icons.text": "Texte",
|
|
1488
|
+
"icons.tag": "\xC9tiquette",
|
|
1489
|
+
"icons.seo": "SEO",
|
|
1490
|
+
"icons.settings": "Param\xE8tres",
|
|
1491
|
+
"icons.image": "Image",
|
|
1492
|
+
"icons.link": "Lien",
|
|
1493
|
+
"icons.palette": "Palette",
|
|
1494
|
+
"icons.list": "Liste",
|
|
1495
|
+
"icons.globe": "Globe",
|
|
1496
|
+
"icons.info": "Info",
|
|
1497
|
+
sidebarOpens: "S'ouvre en",
|
|
1498
|
+
"opens.drawer": "Tiroir",
|
|
1499
|
+
"opens.modal": "Fen\xEAtre modale",
|
|
1500
|
+
moveUp: "Monter",
|
|
1501
|
+
moveDown: "Descendre",
|
|
1502
|
+
sidebarRemove: "Supprimer l'\xE9l\xE9ment",
|
|
1503
|
+
sidebarFields: "Champs",
|
|
1504
|
+
sidebarInvalid: "Donnez un libell\xE9 \xE0 l'\xE9l\xE9ment (40 caract\xE8res maximum, sans < ni >) et choisissez au moins un champ.",
|
|
1505
|
+
sidebarInvalidSave: "Corrigez les \xE9l\xE9ments de barre lat\xE9rale signal\xE9s ci-dessus avant d'enregistrer.",
|
|
1506
|
+
sidebarAdd: "Ajouter un \xE9l\xE9ment",
|
|
1507
|
+
sidebarLimit: "{max} \xE9l\xE9ments maximum.",
|
|
1508
|
+
restoreProject: "R\xE9tablir les valeurs du projet",
|
|
1509
|
+
resetAll: "R\xE9tablir les valeurs par d\xE9faut",
|
|
1510
|
+
restoreProjectConfirm: "Abandonner tous les r\xE9glages enregistr\xE9s sur cette page et revenir aux valeurs du projet d\xE9finies dans le code ?",
|
|
1511
|
+
resetAllConfirm: "Abandonner tous les r\xE9glages enregistr\xE9s sur cette page et revenir aux valeurs par d\xE9faut ?",
|
|
1512
|
+
restored: "Valeurs r\xE9tablies.",
|
|
1513
|
+
blockPreview: "Aper\xE7u en direct du bloc",
|
|
1514
|
+
livePreviewFailed: "Aper\xE7u en direct indisponible, l'image est affich\xE9e.",
|
|
1515
|
+
blockPreviewUrl: "URL d'aper\xE7u de bloc",
|
|
1516
|
+
blockPreviewUrlHelp: "Facultatif. Une page de votre frontend qui affiche un seul bloc, montr\xE9e en grand quand on clique sur une carte de la galerie, par ex. http://localhost:3026/fr/block-preview/'{name}'/'{variant}'. Variables : '{uid}', '{name}' (apr\xE8s le point), '{category}' (avant le point), '{variant}' (default), '{locale}'. Vide : la route d'aper\xE7u de page si elle existe, sinon l'image.",
|
|
1517
|
+
rowActions: "Actions pour {label}",
|
|
1518
|
+
selectBlock: "S\xE9lectionner {label}",
|
|
1519
|
+
hiddenBadge: "Masqu\xE9",
|
|
1520
|
+
hideBlock: "Masquer {label} sur le site",
|
|
1521
|
+
showBlock: "Afficher {label} sur le site",
|
|
1522
|
+
duplicateBlock: "Dupliquer {label}",
|
|
1523
|
+
copyBlock: "Copier {label}",
|
|
1524
|
+
confirmDeleteTitle: "Supprimer le bloc",
|
|
1525
|
+
confirmDelete: "Supprimer le bloc {name} ?",
|
|
1526
|
+
confirmDeleteMarker: "C'est un marqueur de groupe : seul le marqueur est supprim\xE9, pas les blocs du groupe, et le groupe reste d\xE9s\xE9quilibr\xE9 jusqu'\xE0 sa correction.",
|
|
1527
|
+
delete: "Supprimer",
|
|
1528
|
+
selectMode: "S\xE9lectionner des blocs \xE0 copier",
|
|
1529
|
+
copySelected: "Copier la s\xE9lection ({count})",
|
|
1530
|
+
paste: "Coller {count, plural, one {# bloc} other {# blocs}}",
|
|
1531
|
+
pasted: "{count, plural, one {# bloc coll\xE9} other {# blocs coll\xE9s}}.",
|
|
1532
|
+
copied: "{count, plural, one {# bloc copi\xE9} other {# blocs copi\xE9s}}. Collez-les sur n'importe quelle page de ce site.",
|
|
1533
|
+
copyFailed: "Copie impossible : le stockage du navigateur est plein ou bloqu\xE9.",
|
|
1534
|
+
pasteNotAllowed: "Rien n'a \xE9t\xE9 coll\xE9 : \xAB {uid} \xBB n'est pas autoris\xE9 dans cette zone.",
|
|
1535
|
+
pasteFull: "Rien n'a \xE9t\xE9 coll\xE9 : la zone n'a pas de place pour {count} blocs de plus.",
|
|
1536
|
+
pasteUnbalanced: "Rien n'a \xE9t\xE9 coll\xE9 : les blocs copi\xE9s contiennent un groupe incomplet.",
|
|
1537
|
+
rowActionFailed: "L'action n'a pas abouti ; le formulaire n'a pas chang\xE9.",
|
|
1538
|
+
rowActionsTitle: "Actions des blocs",
|
|
1539
|
+
confirmDeleteOption: "Confirmer avant de supprimer un bloc",
|
|
1540
|
+
duplicateOption: "Afficher \xAB Dupliquer \xBB sur chaque bloc",
|
|
1541
|
+
clipboardOption: "Afficher \xAB Copier \xBB et \xAB Coller \xBB (entre pages)",
|
|
1542
|
+
hiddenBlocks: "Blocs masqu\xE9s sur le site",
|
|
1543
|
+
"hiddenModes.strip": "Retir\xE9s de l'API de contenu",
|
|
1544
|
+
"hiddenModes.flag": "Envoy\xE9s avec l'indicateur (le frontend d\xE9cide)",
|
|
1545
|
+
"hiddenModes.off": "D\xE9sactiv\xE9 (pas de bouton masquer)",
|
|
1546
|
+
hiddenBlocksHelp: "L'\u0153il de chaque bloc le marque comme masqu\xE9 sur le site. Retir\xE9s : les lectures de l'API de contenu (REST, GraphQL) l'omettent, l'admin l'affiche toujours. Indicateur : il est envoy\xE9 avec l'attribut et le frontend d\xE9cide.",
|
|
1547
|
+
hiddenAttributeOff: "La configuration du plugin fixe hiddenAttribute \xE0 false : les blocs ne peuvent pas \xEAtre masqu\xE9s."
|
|
704
1548
|
};
|
|
705
1549
|
|
|
706
1550
|
// admin/translations/es.json
|
|
@@ -745,10 +1589,11 @@ var es_default = {
|
|
|
745
1589
|
"templates.faq": "FAQ",
|
|
746
1590
|
brokenMedia: "El medio elegido ya no existe; se usa el siguiente origen.",
|
|
747
1591
|
editor: "Preferencias del editor",
|
|
748
|
-
enabled: "
|
|
749
|
-
enabledHelp: "Desactivado
|
|
1592
|
+
enabled: "Blockscene activado",
|
|
1593
|
+
enabledHelp: "Desactivado, todo el plugin se detiene al instante, sin reinicio: cada vista de edici\xF3n vuelve a ser nativa y se detiene la verificaci\xF3n de grupos al publicar. \xDAsalo si algo falla en producci\xF3n.",
|
|
750
1594
|
showOpenAll: "Mostrar \xABAbrir todos los bloques\xBB",
|
|
751
1595
|
showCloseAll: "Mostrar \xABCerrar todos los bloques\xBB",
|
|
1596
|
+
showRowThumbnails: "Mostrar miniaturas de los bloques en las filas",
|
|
752
1597
|
initialState: "Estado inicial de los acordeones",
|
|
753
1598
|
"states.closed": "Todos cerrados",
|
|
754
1599
|
"states.open": "Todos abiertos",
|
|
@@ -760,13 +1605,20 @@ var es_default = {
|
|
|
760
1605
|
"modes.form": "Campos",
|
|
761
1606
|
"modes.split": "Campos + p\xE1gina",
|
|
762
1607
|
"modes.preview": "Editor visual",
|
|
763
|
-
previewModeHelp: "
|
|
1608
|
+
previewModeHelp: "Cada vista de edici\xF3n se abre en este modo, salvo que su tipo de contenido defina el suyo abajo. Quien edita puede cambiarlo mientras edita; el cambio no se recuerda.",
|
|
1609
|
+
lazyEdit: "Haz clic para editar",
|
|
1610
|
+
lazyEditors: "Cargar los editores de texto enriquecido bajo demanda",
|
|
1611
|
+
lazyFields: "Campos personalizados cargados bajo demanda",
|
|
1612
|
+
lazyEditorsHelp: "Los campos personalizados de la lista muestran una vista previa de solo lectura hasta recibir un clic o el foco, para que las p\xE1ginas grandes abran r\xE1pido. Separa los uids con comas.",
|
|
1613
|
+
lazyFieldsInvalid: "Usa hasta {max} uids de campos personalizados, como plugin::ckeditor5.CKEditor o global::mi-campo.",
|
|
764
1614
|
previewV4: "La vista previa de p\xE1gina completa solo existe en la distribuci\xF3n Strapi 5; estas opciones no tienen efecto en Strapi 4.",
|
|
765
1615
|
modeForm: "Campos",
|
|
766
1616
|
modeSplit: "Campos + p\xE1gina",
|
|
767
1617
|
modePreview: "Editor visual",
|
|
768
1618
|
previewPane: "Vista previa de la p\xE1gina",
|
|
769
1619
|
resize: "Redimensionar el panel de vista previa",
|
|
1620
|
+
resizeHint: "Arrastra para redimensionar; doble clic vuelve a la mitad",
|
|
1621
|
+
scrollToHovered: "Desplazarse al bloque resaltado",
|
|
770
1622
|
previewHelp: "Los cambios sin guardar aparecen en la vista previa. Haga clic en un bloque para abrir su formulario, en una imagen para abrir la Biblioteca multimedia, en un texto para editarlo.",
|
|
771
1623
|
previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
|
|
772
1624
|
previewFailed: "La vista previa no respondi\xF3 en 15 s. Si el frontend a\xFAn est\xE1 cargando, aparecer\xE1 sola; el formulario sigue utilizable.",
|
|
@@ -803,19 +1655,137 @@ var es_default = {
|
|
|
803
1655
|
diagInsertClose: "Insertar el cierre \xAB{expected}\xBB que falta despu\xE9s de la fila {n}",
|
|
804
1656
|
diagStrayHint: "Elimine el marcador hu\xE9rfano con la acci\xF3n de borrar de la propia fila, o mu\xE9valo despu\xE9s de una apertura.",
|
|
805
1657
|
modeGroup: "Modo de edici\xF3n",
|
|
1658
|
+
undo: "Deshacer",
|
|
1659
|
+
redo: "Rehacer",
|
|
1660
|
+
historyGroup: "Historial de cambios",
|
|
806
1661
|
saveDisabledHint: "No hay cambios que guardar.",
|
|
807
1662
|
publishDisabledHint: "Publicaci\xF3n no disponible: guarde antes, corrija los errores del formulario o compruebe sus permisos.",
|
|
808
1663
|
countAll: "{count} bloques",
|
|
809
1664
|
countFiltered: "{shown} de {total}",
|
|
810
|
-
filterCategory: "Filtrar por categor\xEDa",
|
|
811
|
-
allCategories: "Todas las categor\xEDas",
|
|
812
1665
|
showFields: "Campos",
|
|
813
1666
|
showFieldsHint: "Mostrar la lista de campos en cada bloque",
|
|
814
1667
|
columns: "Columnas",
|
|
815
1668
|
noPreview: "sin vista previa",
|
|
816
1669
|
"templates.none": "Sin vista previa",
|
|
817
1670
|
noChanges: "Sin cambios pendientes",
|
|
818
|
-
rowPreview: "Abrir la vista previa de {label}"
|
|
1671
|
+
rowPreview: "Abrir la vista previa de {label}",
|
|
1672
|
+
deviceGroup: "Ancho de la vista previa",
|
|
1673
|
+
"device.fit": "Ajustar",
|
|
1674
|
+
"device.mobile": "M\xF3vil",
|
|
1675
|
+
"device.tablet": "Tableta",
|
|
1676
|
+
"device.desktop": "Escritorio",
|
|
1677
|
+
contentTypes: "Tipos de contenido",
|
|
1678
|
+
contentTypesHelp: 'La galer\xEDa, los acordeones y la vista previa de p\xE1gina funcionan en estos tipos de contenido (los que tienen una Dynamic Zone). Desactiva uno para dejar su edici\xF3n nativa. "Se abre en" define c\xF3mo empieza cada vista de edici\xF3n de ese tipo; quien edita puede cambiarlo mientras edita.',
|
|
1679
|
+
typeMode: "Se abre en",
|
|
1680
|
+
modeDefault: "Predeterminado ({mode})",
|
|
1681
|
+
blockModalDone: "Listo",
|
|
1682
|
+
crashed: "Blockscene se detuvo aqu\xED por un error. El editor nativo no se ve afectado. Si vuelve a pasar, desactiva Blockscene en Settings, Blockscene.",
|
|
1683
|
+
sidebarLabel: "Campos de la p\xE1gina",
|
|
1684
|
+
"nav.all": "Todos",
|
|
1685
|
+
"nav.recent": "Usados recientemente",
|
|
1686
|
+
"nav.starred": "Favoritos",
|
|
1687
|
+
typologiesTitle: "Tipolog\xEDas",
|
|
1688
|
+
collapseSidebar: "Contraer barra lateral",
|
|
1689
|
+
expandSidebar: "Expandir barra lateral",
|
|
1690
|
+
"filters.tags": "Etiquetas",
|
|
1691
|
+
"filters.media": "Medios",
|
|
1692
|
+
"filters.content": "Contenido",
|
|
1693
|
+
clearAll: "Borrar todo",
|
|
1694
|
+
removeFilter: "Quitar filtro {name}",
|
|
1695
|
+
"typologies.hero": "Hero",
|
|
1696
|
+
"typologies.text": "Texto",
|
|
1697
|
+
"typologies.media": "Medios",
|
|
1698
|
+
"typologies.listing": "Listado",
|
|
1699
|
+
"typologies.cards": "Tarjetas",
|
|
1700
|
+
"typologies.cta": "Llamada a la acci\xF3n",
|
|
1701
|
+
"typologies.form": "Formulario",
|
|
1702
|
+
"typologies.layout": "Dise\xF1o",
|
|
1703
|
+
"facets.image": "Imagen",
|
|
1704
|
+
"facets.video": "V\xEDdeo",
|
|
1705
|
+
"facets.gallery": "Galer\xEDa",
|
|
1706
|
+
"facets.richtext": "Texto enriquecido",
|
|
1707
|
+
"facets.list": "Lista",
|
|
1708
|
+
"facets.dynamic": "Din\xE1mico",
|
|
1709
|
+
"facets.form": "Formulario",
|
|
1710
|
+
star: "Marcar como favorito",
|
|
1711
|
+
unstar: "Quitar de favoritos",
|
|
1712
|
+
quickInsert: "Insertar {label}",
|
|
1713
|
+
insert: "Insertar",
|
|
1714
|
+
closeDetail: "Cerrar detalles",
|
|
1715
|
+
typology: "Tipolog\xEDa",
|
|
1716
|
+
typologyAuto: "Autom\xE1tica ({name})",
|
|
1717
|
+
tags: "Etiquetas",
|
|
1718
|
+
tagsHelp: "Separadas por comas, hasta 10 etiquetas de 24 caracteres. Se convierten en un filtro de la galer\xEDa.",
|
|
1719
|
+
sidebarTitle: "Barra lateral del editor visual: {name}",
|
|
1720
|
+
sidebarHelp: "Botones en un borde del editor visual. Cada uno abre algunos campos del propio documento en un caj\xF3n o un modal.",
|
|
1721
|
+
sidebarPosition: "Posici\xF3n de la barra lateral",
|
|
1722
|
+
"positions.left": "Izquierda",
|
|
1723
|
+
"positions.right": "Derecha",
|
|
1724
|
+
"positions.bottom": "Abajo",
|
|
1725
|
+
sidebarItemLabel: "Etiqueta",
|
|
1726
|
+
sidebarIcon: "Icono",
|
|
1727
|
+
noIcon: "Sin icono",
|
|
1728
|
+
"icons.text": "Texto",
|
|
1729
|
+
"icons.tag": "Etiqueta",
|
|
1730
|
+
"icons.seo": "SEO",
|
|
1731
|
+
"icons.settings": "Ajustes",
|
|
1732
|
+
"icons.image": "Imagen",
|
|
1733
|
+
"icons.link": "Enlace",
|
|
1734
|
+
"icons.palette": "Paleta",
|
|
1735
|
+
"icons.list": "Lista",
|
|
1736
|
+
"icons.globe": "Globo",
|
|
1737
|
+
"icons.info": "Informaci\xF3n",
|
|
1738
|
+
sidebarOpens: "Se abre como",
|
|
1739
|
+
"opens.drawer": "Caj\xF3n",
|
|
1740
|
+
"opens.modal": "Modal",
|
|
1741
|
+
moveUp: "Subir",
|
|
1742
|
+
moveDown: "Bajar",
|
|
1743
|
+
sidebarRemove: "Quitar elemento",
|
|
1744
|
+
sidebarFields: "Campos",
|
|
1745
|
+
sidebarInvalid: "Pon una etiqueta al elemento (hasta 40 caracteres, sin < ni >) y elige al menos un campo.",
|
|
1746
|
+
sidebarInvalidSave: "Corrige los elementos de la barra lateral marcados arriba antes de guardar.",
|
|
1747
|
+
sidebarAdd: "A\xF1adir elemento",
|
|
1748
|
+
sidebarLimit: "Hasta {max} elementos.",
|
|
1749
|
+
restoreProject: "Restaurar valores del proyecto",
|
|
1750
|
+
resetAll: "Restablecer valores predeterminados",
|
|
1751
|
+
restoreProjectConfirm: "\xBFDescartar todos los ajustes guardados en esta p\xE1gina y volver a los valores del proyecto definidos en el c\xF3digo?",
|
|
1752
|
+
resetAllConfirm: "\xBFDescartar todos los ajustes guardados en esta p\xE1gina y volver a los valores predeterminados?",
|
|
1753
|
+
restored: "Valores restablecidos.",
|
|
1754
|
+
blockPreview: "Vista previa en vivo del bloque",
|
|
1755
|
+
livePreviewFailed: "Vista previa en vivo no disponible, se muestra la imagen.",
|
|
1756
|
+
blockPreviewUrl: "URL de vista previa del bloque",
|
|
1757
|
+
blockPreviewUrlHelp: "Opcional. Una p\xE1gina de su frontend que renderiza un solo bloque, mostrada en grande al hacer clic en una tarjeta de la galer\xEDa, p. ej. http://localhost:3026/es/block-preview/'{name}'/'{variant}'. Marcadores: '{uid}', '{name}' (tras el punto), '{category}' (antes del punto), '{variant}' (default), '{locale}'. Vac\xEDa usa la ruta de vista previa de p\xE1gina si existe; si no, la imagen.",
|
|
1758
|
+
rowActions: "Acciones de {label}",
|
|
1759
|
+
selectBlock: "Seleccionar {label}",
|
|
1760
|
+
hiddenBadge: "Oculto",
|
|
1761
|
+
hideBlock: "Ocultar {label} en el sitio",
|
|
1762
|
+
showBlock: "Mostrar {label} en el sitio",
|
|
1763
|
+
duplicateBlock: "Duplicar {label}",
|
|
1764
|
+
copyBlock: "Copiar {label}",
|
|
1765
|
+
confirmDeleteTitle: "Eliminar bloque",
|
|
1766
|
+
confirmDelete: "\xBFEliminar el bloque {name}?",
|
|
1767
|
+
confirmDeleteMarker: "Es un marcador de grupo: solo se elimina el marcador, no los bloques del grupo, y el grupo queda desequilibrado hasta corregirlo.",
|
|
1768
|
+
delete: "Eliminar",
|
|
1769
|
+
selectMode: "Seleccionar bloques para copiar",
|
|
1770
|
+
copySelected: "Copiar seleccionados ({count})",
|
|
1771
|
+
paste: "Pegar {count, plural, one {# bloque} other {# bloques}}",
|
|
1772
|
+
pasted: "{count, plural, one {# bloque pegado} other {# bloques pegados}}.",
|
|
1773
|
+
copied: "{count, plural, one {# bloque copiado} other {# bloques copiados}}. P\xE9galos en cualquier p\xE1gina de este sitio.",
|
|
1774
|
+
copyFailed: "No se pudo copiar: el almacenamiento del navegador est\xE1 lleno o bloqueado.",
|
|
1775
|
+
pasteNotAllowed: "No se peg\xF3 nada: \xAB{uid}\xBB no est\xE1 permitido en esta zona.",
|
|
1776
|
+
pasteFull: "No se peg\xF3 nada: la zona no tiene espacio para {count} bloques m\xE1s.",
|
|
1777
|
+
pasteUnbalanced: "No se peg\xF3 nada: los bloques copiados contienen un grupo incompleto.",
|
|
1778
|
+
rowActionFailed: "No se pudo completar la acci\xF3n; el formulario no cambi\xF3.",
|
|
1779
|
+
rowActionsTitle: "Acciones de los bloques",
|
|
1780
|
+
confirmDeleteOption: "Confirmar antes de eliminar un bloque",
|
|
1781
|
+
duplicateOption: "Mostrar \xABDuplicar\xBB en cada bloque",
|
|
1782
|
+
clipboardOption: "Mostrar \xABCopiar\xBB y \xABPegar\xBB (entre p\xE1ginas)",
|
|
1783
|
+
hiddenBlocks: "Bloques ocultos en el sitio",
|
|
1784
|
+
"hiddenModes.strip": "Eliminados de la API de contenido",
|
|
1785
|
+
"hiddenModes.flag": "Enviados con la marca (el frontend decide)",
|
|
1786
|
+
"hiddenModes.off": "Desactivado (sin bot\xF3n de ocultar)",
|
|
1787
|
+
hiddenBlocksHelp: "El ojo de cada bloque lo marca como oculto en el sitio. Eliminados: las lecturas de la API de contenido (REST, GraphQL) lo omiten; el admin siempre lo muestra. Marca: se env\xEDa con el atributo y el frontend decide.",
|
|
1788
|
+
hiddenAttributeOff: "La configuraci\xF3n del plugin fija hiddenAttribute en false: no se pueden ocultar bloques."
|
|
819
1789
|
};
|
|
820
1790
|
|
|
821
1791
|
// admin/translations/de.json
|
|
@@ -860,10 +1830,11 @@ var de_default = {
|
|
|
860
1830
|
"templates.faq": "FAQ",
|
|
861
1831
|
brokenMedia: "Das gew\xE4hlte Medium existiert nicht mehr; die n\xE4chste Quelle wird verwendet.",
|
|
862
1832
|
editor: "Editor-Einstellungen",
|
|
863
|
-
enabled: "
|
|
864
|
-
enabledHelp: "Aus
|
|
1833
|
+
enabled: "Blockscene aktiv",
|
|
1834
|
+
enabledHelp: "Aus schaltet das ganze Plugin sofort ab, ohne Neustart: jede Bearbeitungsansicht ist wieder nativ und die Gruppenpr\xFCfung beim Ver\xF6ffentlichen stoppt. F\xFCr den Fall, dass in Produktion etwas schiefgeht.",
|
|
865
1835
|
showOpenAll: "\u201EAlle Bl\xF6cke \xF6ffnen\u201C anzeigen",
|
|
866
1836
|
showCloseAll: "\u201EAlle Bl\xF6cke schlie\xDFen\u201C anzeigen",
|
|
1837
|
+
showRowThumbnails: "Blockvorschaubilder in den Zeilen anzeigen",
|
|
867
1838
|
initialState: "Anfangszustand der Akkordeons",
|
|
868
1839
|
"states.closed": "Alle geschlossen",
|
|
869
1840
|
"states.open": "Alle ge\xF6ffnet",
|
|
@@ -875,13 +1846,20 @@ var de_default = {
|
|
|
875
1846
|
"modes.form": "Felder",
|
|
876
1847
|
"modes.split": "Felder + Seite",
|
|
877
1848
|
"modes.preview": "Visueller Editor",
|
|
878
|
-
previewModeHelp: "
|
|
1849
|
+
previewModeHelp: "Jede Bearbeitungsansicht \xF6ffnet in diesem Modus, au\xDFer ihr Inhaltstyp legt unten einen eigenen fest. Beim Bearbeiten l\xE4sst sich wechseln; der Wechsel wird nicht gespeichert.",
|
|
1850
|
+
lazyEdit: "Zum Bearbeiten klicken",
|
|
1851
|
+
lazyEditors: "Rich-Text-Editoren bei Bedarf laden",
|
|
1852
|
+
lazyFields: "Bei Bedarf geladene benutzerdefinierte Felder",
|
|
1853
|
+
lazyEditorsHelp: "Die aufgef\xFChrten benutzerdefinierten Felder zeigen eine schreibgesch\xFCtzte Vorschau, bis sie angeklickt oder fokussiert werden, damit gro\xDFe Seiten schnell \xF6ffnen. Uids durch Kommas trennen.",
|
|
1854
|
+
lazyFieldsInvalid: "Bis zu {max} Uids benutzerdefinierter Felder verwenden, z. B. plugin::ckeditor5.CKEditor oder global::mein-feld.",
|
|
879
1855
|
previewV4: "Die Ganzseiten-Vorschau gibt es nur in der Strapi-5-Distribution; diese Optionen haben unter Strapi 4 keine Wirkung.",
|
|
880
1856
|
modeForm: "Felder",
|
|
881
1857
|
modeSplit: "Felder + Seite",
|
|
882
1858
|
modePreview: "Visueller Editor",
|
|
883
1859
|
previewPane: "Seitenvorschau",
|
|
884
1860
|
resize: "Vorschaubereich anpassen",
|
|
1861
|
+
resizeHint: "Ziehen zum \xC4ndern der Gr\xF6\xDFe; Doppelklick setzt auf die H\xE4lfte zur\xFCck",
|
|
1862
|
+
scrollToHovered: "Zum hervorgehobenen Block scrollen",
|
|
885
1863
|
previewHelp: "Ungespeicherte \xC4nderungen erscheinen in der Vorschau. Klicken Sie auf einen Block, um sein Formular zu \xF6ffnen, auf ein Bild f\xFCr die Medienbibliothek, auf einen Text, um ihn zu bearbeiten.",
|
|
886
1864
|
previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
|
|
887
1865
|
previewFailed: "Die Vorschau hat innerhalb von 15 s nicht geantwortet. L\xE4dt das Frontend noch, erscheint sie von selbst; das Formular bleibt benutzbar.",
|
|
@@ -918,19 +1896,137 @@ var de_default = {
|
|
|
918
1896
|
diagInsertClose: "Fehlenden Schlie\xDFmarker \u201E{expected}\u201C nach Zeile {n} einf\xFCgen",
|
|
919
1897
|
diagStrayHint: "Entfernen Sie den verwaisten Marker \xFCber die L\xF6schaktion der Zeile oder verschieben Sie ihn hinter einen \xD6ffnungsmarker.",
|
|
920
1898
|
modeGroup: "Bearbeitungsmodus",
|
|
1899
|
+
undo: "R\xFCckg\xE4ngig",
|
|
1900
|
+
redo: "Wiederholen",
|
|
1901
|
+
historyGroup: "Bearbeitungsverlauf",
|
|
921
1902
|
saveDisabledHint: "Keine ungespeicherten \xC4nderungen.",
|
|
922
1903
|
publishDisabledHint: "Ver\xF6ffentlichen nicht m\xF6glich: zuerst speichern, Formularfehler beheben oder Berechtigungen pr\xFCfen.",
|
|
923
1904
|
countAll: "{count} Bl\xF6cke",
|
|
924
1905
|
countFiltered: "{shown} von {total}",
|
|
925
|
-
filterCategory: "Nach Kategorie filtern",
|
|
926
|
-
allCategories: "Alle Kategorien",
|
|
927
1906
|
showFields: "Felder",
|
|
928
1907
|
showFieldsHint: "Feldliste auf jedem Block anzeigen",
|
|
929
1908
|
columns: "Spalten",
|
|
930
1909
|
noPreview: "keine Vorschau",
|
|
931
1910
|
"templates.none": "Keine Vorschau",
|
|
932
1911
|
noChanges: "Keine ungespeicherten \xC4nderungen",
|
|
933
|
-
rowPreview: "Vorschau von {label} \xF6ffnen"
|
|
1912
|
+
rowPreview: "Vorschau von {label} \xF6ffnen",
|
|
1913
|
+
deviceGroup: "Vorschaubreite",
|
|
1914
|
+
"device.fit": "Anpassen",
|
|
1915
|
+
"device.mobile": "Mobil",
|
|
1916
|
+
"device.tablet": "Tablet",
|
|
1917
|
+
"device.desktop": "Desktop",
|
|
1918
|
+
contentTypes: "Inhaltstypen",
|
|
1919
|
+
contentTypesHelp: "Galerie, Akkordeons und Seitenvorschau arbeiten auf diesen Inhaltstypen (denen mit einer Dynamic Zone). Schalte einen aus, um seine Bearbeitung nativ zu lassen. \u201E\xD6ffnet in\u201C bestimmt, wie jede Bearbeitungsansicht dieses Typs startet; beim Bearbeiten l\xE4sst sich weiter wechseln.",
|
|
1920
|
+
typeMode: "\xD6ffnet in",
|
|
1921
|
+
modeDefault: "Standard ({mode})",
|
|
1922
|
+
blockModalDone: "Fertig",
|
|
1923
|
+
crashed: "Blockscene wurde hier wegen eines Fehlers beendet. Der native Editor ist nicht betroffen. Passiert es erneut, schalte Blockscene unter Settings, Blockscene aus.",
|
|
1924
|
+
sidebarLabel: "Seitenfelder",
|
|
1925
|
+
"nav.all": "Alle",
|
|
1926
|
+
"nav.recent": "Zuletzt verwendet",
|
|
1927
|
+
"nav.starred": "Favoriten",
|
|
1928
|
+
typologiesTitle: "Typologien",
|
|
1929
|
+
collapseSidebar: "Seitenleiste einklappen",
|
|
1930
|
+
expandSidebar: "Seitenleiste ausklappen",
|
|
1931
|
+
"filters.tags": "Tags",
|
|
1932
|
+
"filters.media": "Medien",
|
|
1933
|
+
"filters.content": "Inhalt",
|
|
1934
|
+
clearAll: "Alle entfernen",
|
|
1935
|
+
removeFilter: "Filter {name} entfernen",
|
|
1936
|
+
"typologies.hero": "Hero",
|
|
1937
|
+
"typologies.text": "Text",
|
|
1938
|
+
"typologies.media": "Medien",
|
|
1939
|
+
"typologies.listing": "Auflistung",
|
|
1940
|
+
"typologies.cards": "Karten",
|
|
1941
|
+
"typologies.cta": "Call to Action",
|
|
1942
|
+
"typologies.form": "Formular",
|
|
1943
|
+
"typologies.layout": "Layout",
|
|
1944
|
+
"facets.image": "Bild",
|
|
1945
|
+
"facets.video": "Video",
|
|
1946
|
+
"facets.gallery": "Galerie",
|
|
1947
|
+
"facets.richtext": "Rich Text",
|
|
1948
|
+
"facets.list": "Liste",
|
|
1949
|
+
"facets.dynamic": "Dynamisch",
|
|
1950
|
+
"facets.form": "Formular",
|
|
1951
|
+
star: "Als Favorit markieren",
|
|
1952
|
+
unstar: "Aus Favoriten entfernen",
|
|
1953
|
+
quickInsert: "{label} einf\xFCgen",
|
|
1954
|
+
insert: "Einf\xFCgen",
|
|
1955
|
+
closeDetail: "Details schlie\xDFen",
|
|
1956
|
+
typology: "Typologie",
|
|
1957
|
+
typologyAuto: "Automatisch ({name})",
|
|
1958
|
+
tags: "Tags",
|
|
1959
|
+
tagsHelp: "Kommagetrennt, bis zu 10 Tags mit je 24 Zeichen. Sie werden zu einem Filter der Galerie.",
|
|
1960
|
+
sidebarTitle: "Seitenleiste des visuellen Editors: {name}",
|
|
1961
|
+
sidebarHelp: "Schaltfl\xE4chen an einem Rand des visuellen Editors. Jede \xF6ffnet einige Felder des Dokuments in einer Schublade oder einem Dialog.",
|
|
1962
|
+
sidebarPosition: "Position der Seitenleiste",
|
|
1963
|
+
"positions.left": "Links",
|
|
1964
|
+
"positions.right": "Rechts",
|
|
1965
|
+
"positions.bottom": "Unten",
|
|
1966
|
+
sidebarItemLabel: "Beschriftung",
|
|
1967
|
+
sidebarIcon: "Symbol",
|
|
1968
|
+
noIcon: "Kein Symbol",
|
|
1969
|
+
"icons.text": "Text",
|
|
1970
|
+
"icons.tag": "Tag",
|
|
1971
|
+
"icons.seo": "SEO",
|
|
1972
|
+
"icons.settings": "Einstellungen",
|
|
1973
|
+
"icons.image": "Bild",
|
|
1974
|
+
"icons.link": "Link",
|
|
1975
|
+
"icons.palette": "Palette",
|
|
1976
|
+
"icons.list": "Liste",
|
|
1977
|
+
"icons.globe": "Globus",
|
|
1978
|
+
"icons.info": "Info",
|
|
1979
|
+
sidebarOpens: "\xD6ffnet als",
|
|
1980
|
+
"opens.drawer": "Schublade",
|
|
1981
|
+
"opens.modal": "Dialog",
|
|
1982
|
+
moveUp: "Nach oben",
|
|
1983
|
+
moveDown: "Nach unten",
|
|
1984
|
+
sidebarRemove: "Eintrag entfernen",
|
|
1985
|
+
sidebarFields: "Felder",
|
|
1986
|
+
sidebarInvalid: "Gib dem Eintrag eine Beschriftung (bis zu 40 Zeichen, ohne < oder >) und w\xE4hle mindestens ein Feld.",
|
|
1987
|
+
sidebarInvalidSave: "Korrigiere die oben markierten Seitenleisteneintr\xE4ge vor dem Speichern.",
|
|
1988
|
+
sidebarAdd: "Eintrag hinzuf\xFCgen",
|
|
1989
|
+
sidebarLimit: "Bis zu {max} Eintr\xE4ge.",
|
|
1990
|
+
restoreProject: "Projektstandards wiederherstellen",
|
|
1991
|
+
resetAll: "Auf Standard zur\xFCcksetzen",
|
|
1992
|
+
restoreProjectConfirm: "Alle auf dieser Seite gespeicherten Einstellungen verwerfen und zu den Projektstandards aus dem Code zur\xFCckkehren?",
|
|
1993
|
+
resetAllConfirm: "Alle auf dieser Seite gespeicherten Einstellungen verwerfen und zu den Standardwerten zur\xFCckkehren?",
|
|
1994
|
+
restored: "Standards wiederhergestellt.",
|
|
1995
|
+
blockPreview: "Live-Vorschau des Blocks",
|
|
1996
|
+
livePreviewFailed: "Live-Vorschau nicht verf\xFCgbar, das Bild wird angezeigt.",
|
|
1997
|
+
blockPreviewUrl: "Block-Vorschau-URL",
|
|
1998
|
+
blockPreviewUrlHelp: "Optional. Eine Seite Ihres Frontends, die einen einzelnen Block rendert und beim Klick auf eine Galeriekarte gro\xDF angezeigt wird, z. B. http://localhost:3026/de/block-preview/'{name}'/'{variant}'. Platzhalter: '{uid}', '{name}' (nach dem Punkt), '{category}' (vor dem Punkt), '{variant}' (default), '{locale}'. Leer verwendet die Seitenvorschau-Route, falls vorhanden, sonst das Bild.",
|
|
1999
|
+
rowActions: "Aktionen f\xFCr {label}",
|
|
2000
|
+
selectBlock: "{label} ausw\xE4hlen",
|
|
2001
|
+
hiddenBadge: "Ausgeblendet",
|
|
2002
|
+
hideBlock: "{label} auf der Website ausblenden",
|
|
2003
|
+
showBlock: "{label} auf der Website anzeigen",
|
|
2004
|
+
duplicateBlock: "{label} duplizieren",
|
|
2005
|
+
copyBlock: "{label} kopieren",
|
|
2006
|
+
confirmDeleteTitle: "Block l\xF6schen",
|
|
2007
|
+
confirmDelete: "Block {name} l\xF6schen?",
|
|
2008
|
+
confirmDeleteMarker: "Dies ist eine Gruppenmarkierung: Nur die Markierung wird entfernt, nicht die Bl\xF6cke der Gruppe, und die Gruppe bleibt unausgeglichen, bis sie korrigiert ist.",
|
|
2009
|
+
delete: "L\xF6schen",
|
|
2010
|
+
selectMode: "Bl\xF6cke zum Kopieren ausw\xE4hlen",
|
|
2011
|
+
copySelected: "Auswahl kopieren ({count})",
|
|
2012
|
+
paste: "{count, plural, one {# Block} other {# Bl\xF6cke}} einf\xFCgen",
|
|
2013
|
+
pasted: "{count, plural, one {# Block eingef\xFCgt} other {# Bl\xF6cke eingef\xFCgt}}.",
|
|
2014
|
+
copied: "{count, plural, one {# Block kopiert} other {# Bl\xF6cke kopiert}}. Auf jeder Seite dieser Website einf\xFCgbar.",
|
|
2015
|
+
copyFailed: "Kopieren nicht m\xF6glich: Der Browserspeicher ist voll oder gesperrt.",
|
|
2016
|
+
pasteNotAllowed: "Nichts eingef\xFCgt: \u201E{uid}\u201C ist in dieser Zone nicht erlaubt.",
|
|
2017
|
+
pasteFull: "Nichts eingef\xFCgt: Die Zone hat keinen Platz f\xFCr {count} weitere Bl\xF6cke.",
|
|
2018
|
+
pasteUnbalanced: "Nichts eingef\xFCgt: Die kopierten Bl\xF6cke enthalten eine unvollst\xE4ndige Gruppe.",
|
|
2019
|
+
rowActionFailed: "Die Aktion konnte nicht ausgef\xFChrt werden; das Formular wurde nicht ge\xE4ndert.",
|
|
2020
|
+
rowActionsTitle: "Block-Aktionen",
|
|
2021
|
+
confirmDeleteOption: "Vor dem L\xF6schen eines Blocks nachfragen",
|
|
2022
|
+
duplicateOption: "\u201EDuplizieren\u201C an jedem Block anzeigen",
|
|
2023
|
+
clipboardOption: "\u201EKopieren\u201C und \u201EEinf\xFCgen\u201C anzeigen (seiten\xFCbergreifend)",
|
|
2024
|
+
hiddenBlocks: "Auf der Website ausgeblendete Bl\xF6cke",
|
|
2025
|
+
"hiddenModes.strip": "Aus der Content-API entfernt",
|
|
2026
|
+
"hiddenModes.flag": "Mit Markierung gesendet (das Frontend entscheidet)",
|
|
2027
|
+
"hiddenModes.off": "Aus (kein Ausblenden-Knopf)",
|
|
2028
|
+
hiddenBlocksHelp: "Das Auge an jedem Block blendet ihn auf der Website aus. Entfernt: Lesezugriffe der Content-API (REST, GraphQL) lassen ihn weg, der Admin zeigt ihn immer. Markierung: Er wird mit dem Attribut gesendet und das Frontend entscheidet.",
|
|
2029
|
+
hiddenAttributeOff: "Die Plugin-Konfiguration setzt hiddenAttribute auf false: Bl\xF6cke k\xF6nnen nicht ausgeblendet werden."
|
|
934
2030
|
};
|
|
935
2031
|
|
|
936
2032
|
// admin/translations/it.json
|
|
@@ -975,10 +2071,11 @@ var it_default = {
|
|
|
975
2071
|
"templates.faq": "FAQ",
|
|
976
2072
|
brokenMedia: "Il media scelto non esiste pi\xF9; viene usata l'origine successiva.",
|
|
977
2073
|
editor: "Preferenze dell'editor",
|
|
978
|
-
enabled: "
|
|
979
|
-
enabledHelp: "Disattivato
|
|
2074
|
+
enabled: "Blockscene attivo",
|
|
2075
|
+
enabledHelp: "Disattivato, l'intero plugin si ferma subito, senza riavvio: ogni vista di modifica torna nativa e il controllo dei gruppi alla pubblicazione si ferma. Da usare se qualcosa va storto in produzione.",
|
|
980
2076
|
showOpenAll: 'Mostra "Apri tutti i blocchi"',
|
|
981
2077
|
showCloseAll: 'Mostra "Chiudi tutti i blocchi"',
|
|
2078
|
+
showRowThumbnails: "Mostra le miniature dei blocchi nelle righe",
|
|
982
2079
|
initialState: "Stato iniziale delle fisarmoniche",
|
|
983
2080
|
"states.closed": "Tutte chiuse",
|
|
984
2081
|
"states.open": "Tutte aperte",
|
|
@@ -990,13 +2087,20 @@ var it_default = {
|
|
|
990
2087
|
"modes.form": "Campi",
|
|
991
2088
|
"modes.split": "Campi + pagina",
|
|
992
2089
|
"modes.preview": "Editor visivo",
|
|
993
|
-
previewModeHelp: "
|
|
2090
|
+
previewModeHelp: "Ogni vista di modifica si apre in questo modo, a meno che il suo tipo di contenuto ne imposti uno proprio qui sotto. Durante la modifica si pu\xF2 cambiare; la scelta non viene ricordata.",
|
|
2091
|
+
lazyEdit: "Fai clic per modificare",
|
|
2092
|
+
lazyEditors: "Carica gli editor di testo formattato su richiesta",
|
|
2093
|
+
lazyFields: "Campi personalizzati caricati su richiesta",
|
|
2094
|
+
lazyEditorsHelp: "I campi personalizzati elencati mostrano un'anteprima di sola lettura finch\xE9 non ricevono un clic o il focus, cos\xEC le pagine grandi si aprono in fretta. Separa gli uid con virgole.",
|
|
2095
|
+
lazyFieldsInvalid: "Usa fino a {max} uid di campi personalizzati, come plugin::ckeditor5.CKEditor o global::mio-campo.",
|
|
994
2096
|
previewV4: "L'anteprima dell'intera pagina esiste solo nella distribuzione Strapi 5; queste opzioni non hanno effetto su Strapi 4.",
|
|
995
2097
|
modeForm: "Campi",
|
|
996
2098
|
modeSplit: "Campi + pagina",
|
|
997
2099
|
modePreview: "Editor visivo",
|
|
998
2100
|
previewPane: "Anteprima della pagina",
|
|
999
2101
|
resize: "Ridimensiona il pannello di anteprima",
|
|
2102
|
+
resizeHint: "Trascina per ridimensionare; doppio clic per tornare a met\xE0",
|
|
2103
|
+
scrollToHovered: "Scorri fino al blocco evidenziato",
|
|
1000
2104
|
previewHelp: "Le modifiche non salvate compaiono nell'anteprima. Clicca un blocco per aprire il suo modulo, un'immagine per aprire la Libreria media, un testo per modificarlo.",
|
|
1001
2105
|
previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
|
|
1002
2106
|
previewFailed: "L'anteprima non ha risposto entro 15 s. Se il frontend sta ancora caricando, comparir\xE0 da sola; il modulo resta utilizzabile.",
|
|
@@ -1033,19 +2137,137 @@ var it_default = {
|
|
|
1033
2137
|
diagInsertClose: 'Inserisci la chiusura "{expected}" mancante dopo la riga {n}',
|
|
1034
2138
|
diagStrayHint: "Rimuovi il marcatore orfano con l'azione di eliminazione della riga, oppure spostalo dopo un'apertura.",
|
|
1035
2139
|
modeGroup: "Modalit\xE0 di modifica",
|
|
2140
|
+
undo: "Annulla",
|
|
2141
|
+
redo: "Ripeti",
|
|
2142
|
+
historyGroup: "Cronologia modifiche",
|
|
1036
2143
|
saveDisabledHint: "Nessuna modifica da salvare.",
|
|
1037
2144
|
publishDisabledHint: "Pubblicazione non disponibile: salva prima, correggi gli errori del modulo o verifica i permessi.",
|
|
1038
2145
|
countAll: "{count} blocchi",
|
|
1039
2146
|
countFiltered: "{shown} di {total}",
|
|
1040
|
-
filterCategory: "Filtra per categoria",
|
|
1041
|
-
allCategories: "Tutte le categorie",
|
|
1042
2147
|
showFields: "Campi",
|
|
1043
2148
|
showFieldsHint: "Mostra l\u2019elenco dei campi su ogni blocco",
|
|
1044
2149
|
columns: "Colonne",
|
|
1045
2150
|
noPreview: "nessuna anteprima",
|
|
1046
2151
|
"templates.none": "Nessuna anteprima",
|
|
1047
2152
|
noChanges: "Nessuna modifica in sospeso",
|
|
1048
|
-
rowPreview: "Apri l\u2019anteprima di {label}"
|
|
2153
|
+
rowPreview: "Apri l\u2019anteprima di {label}",
|
|
2154
|
+
deviceGroup: "Larghezza dell'anteprima",
|
|
2155
|
+
"device.fit": "Adatta",
|
|
2156
|
+
"device.mobile": "Mobile",
|
|
2157
|
+
"device.tablet": "Tablet",
|
|
2158
|
+
"device.desktop": "Desktop",
|
|
2159
|
+
contentTypes: "Tipi di contenuto",
|
|
2160
|
+
contentTypesHelp: "La galleria, le fisarmoniche e l'anteprima di pagina funzionano su questi tipi di contenuto (quelli con una Dynamic Zone). Disattivane uno per lasciarne la modifica nativa. \xABSi apre in\xBB \xE8 il modo in cui parte ogni vista di modifica di quel tipo; durante la modifica si pu\xF2 sempre cambiare.",
|
|
2161
|
+
typeMode: "Si apre in",
|
|
2162
|
+
modeDefault: "Predefinito ({mode})",
|
|
2163
|
+
blockModalDone: "Fatto",
|
|
2164
|
+
crashed: "Blockscene si \xE8 fermato qui a causa di un errore. L'editor nativo non \xE8 toccato. Se succede di nuovo, disattiva Blockscene in Settings, Blockscene.",
|
|
2165
|
+
sidebarLabel: "Campi della pagina",
|
|
2166
|
+
"nav.all": "Tutti",
|
|
2167
|
+
"nav.recent": "Usati di recente",
|
|
2168
|
+
"nav.starred": "Preferiti",
|
|
2169
|
+
typologiesTitle: "Tipologie",
|
|
2170
|
+
collapseSidebar: "Comprimi barra laterale",
|
|
2171
|
+
expandSidebar: "Espandi barra laterale",
|
|
2172
|
+
"filters.tags": "Tag",
|
|
2173
|
+
"filters.media": "Media",
|
|
2174
|
+
"filters.content": "Contenuto",
|
|
2175
|
+
clearAll: "Cancella tutto",
|
|
2176
|
+
removeFilter: "Rimuovi filtro {name}",
|
|
2177
|
+
"typologies.hero": "Hero",
|
|
2178
|
+
"typologies.text": "Testo",
|
|
2179
|
+
"typologies.media": "Media",
|
|
2180
|
+
"typologies.listing": "Elenco",
|
|
2181
|
+
"typologies.cards": "Card",
|
|
2182
|
+
"typologies.cta": "Invito all'azione",
|
|
2183
|
+
"typologies.form": "Modulo",
|
|
2184
|
+
"typologies.layout": "Layout",
|
|
2185
|
+
"facets.image": "Immagine",
|
|
2186
|
+
"facets.video": "Video",
|
|
2187
|
+
"facets.gallery": "Galleria",
|
|
2188
|
+
"facets.richtext": "Testo formattato",
|
|
2189
|
+
"facets.list": "Lista",
|
|
2190
|
+
"facets.dynamic": "Dinamico",
|
|
2191
|
+
"facets.form": "Modulo",
|
|
2192
|
+
star: "Aggiungi ai preferiti",
|
|
2193
|
+
unstar: "Rimuovi dai preferiti",
|
|
2194
|
+
quickInsert: "Inserisci {label}",
|
|
2195
|
+
insert: "Inserisci",
|
|
2196
|
+
closeDetail: "Chiudi dettagli",
|
|
2197
|
+
typology: "Tipologia",
|
|
2198
|
+
typologyAuto: "Automatica ({name})",
|
|
2199
|
+
tags: "Tag",
|
|
2200
|
+
tagsHelp: "Separati da virgole, fino a 10 tag di 24 caratteri. Diventano un filtro della galleria.",
|
|
2201
|
+
sidebarTitle: "Barra laterale dell'editor visivo: {name}",
|
|
2202
|
+
sidebarHelp: "Pulsanti su un bordo dell'editor visivo. Ognuno apre alcuni campi del documento in un pannello laterale o in una finestra modale.",
|
|
2203
|
+
sidebarPosition: "Posizione della barra laterale",
|
|
2204
|
+
"positions.left": "Sinistra",
|
|
2205
|
+
"positions.right": "Destra",
|
|
2206
|
+
"positions.bottom": "In basso",
|
|
2207
|
+
sidebarItemLabel: "Etichetta",
|
|
2208
|
+
sidebarIcon: "Icona",
|
|
2209
|
+
noIcon: "Nessuna icona",
|
|
2210
|
+
"icons.text": "Testo",
|
|
2211
|
+
"icons.tag": "Tag",
|
|
2212
|
+
"icons.seo": "SEO",
|
|
2213
|
+
"icons.settings": "Impostazioni",
|
|
2214
|
+
"icons.image": "Immagine",
|
|
2215
|
+
"icons.link": "Link",
|
|
2216
|
+
"icons.palette": "Tavolozza",
|
|
2217
|
+
"icons.list": "Elenco",
|
|
2218
|
+
"icons.globe": "Globo",
|
|
2219
|
+
"icons.info": "Info",
|
|
2220
|
+
sidebarOpens: "Si apre come",
|
|
2221
|
+
"opens.drawer": "Pannello laterale",
|
|
2222
|
+
"opens.modal": "Finestra modale",
|
|
2223
|
+
moveUp: "Sposta su",
|
|
2224
|
+
moveDown: "Sposta gi\xF9",
|
|
2225
|
+
sidebarRemove: "Rimuovi elemento",
|
|
2226
|
+
sidebarFields: "Campi",
|
|
2227
|
+
sidebarInvalid: "Dai un'etichetta all'elemento (fino a 40 caratteri, senza < o >) e scegli almeno un campo.",
|
|
2228
|
+
sidebarInvalidSave: "Correggi gli elementi della barra laterale segnalati sopra prima di salvare.",
|
|
2229
|
+
sidebarAdd: "Aggiungi elemento",
|
|
2230
|
+
sidebarLimit: "Fino a {max} elementi.",
|
|
2231
|
+
restoreProject: "Ripristina i valori del progetto",
|
|
2232
|
+
resetAll: "Ripristina i valori predefiniti",
|
|
2233
|
+
restoreProjectConfirm: "Scartare tutte le impostazioni salvate in questa pagina e tornare ai valori del progetto definiti nel codice?",
|
|
2234
|
+
resetAllConfirm: "Scartare tutte le impostazioni salvate in questa pagina e tornare ai valori predefiniti?",
|
|
2235
|
+
restored: "Valori ripristinati.",
|
|
2236
|
+
blockPreview: "Anteprima dal vivo del blocco",
|
|
2237
|
+
livePreviewFailed: "Anteprima dal vivo non disponibile, viene mostrata l'immagine.",
|
|
2238
|
+
blockPreviewUrl: "URL di anteprima del blocco",
|
|
2239
|
+
blockPreviewUrlHelp: "Facoltativo. Una pagina del tuo frontend che renderizza un singolo blocco, mostrata in grande quando si clicca una scheda della galleria, ad es. http://localhost:3026/it/block-preview/'{name}'/'{variant}'. Segnaposto: '{uid}', '{name}' (dopo il punto), '{category}' (prima del punto), '{variant}' (default), '{locale}'. Vuoto usa la route di anteprima pagina se esiste, altrimenti l'immagine.",
|
|
2240
|
+
rowActions: "Azioni per {label}",
|
|
2241
|
+
selectBlock: "Seleziona {label}",
|
|
2242
|
+
hiddenBadge: "Nascosto",
|
|
2243
|
+
hideBlock: "Nascondi {label} sul sito",
|
|
2244
|
+
showBlock: "Mostra {label} sul sito",
|
|
2245
|
+
duplicateBlock: "Duplica {label}",
|
|
2246
|
+
copyBlock: "Copia {label}",
|
|
2247
|
+
confirmDeleteTitle: "Elimina blocco",
|
|
2248
|
+
confirmDelete: "Eliminare il blocco {name}?",
|
|
2249
|
+
confirmDeleteMarker: "\xC8 un marcatore di gruppo: viene rimosso solo il marcatore, non i blocchi del gruppo, e il gruppo resta sbilanciato finch\xE9 non viene corretto.",
|
|
2250
|
+
delete: "Elimina",
|
|
2251
|
+
selectMode: "Seleziona i blocchi da copiare",
|
|
2252
|
+
copySelected: "Copia selezionati ({count})",
|
|
2253
|
+
paste: "Incolla {count, plural, one {# blocco} other {# blocchi}}",
|
|
2254
|
+
pasted: "{count, plural, one {# blocco incollato} other {# blocchi incollati}}.",
|
|
2255
|
+
copied: "{count, plural, one {# blocco copiato} other {# blocchi copiati}}. Incollali in qualsiasi pagina di questo sito.",
|
|
2256
|
+
copyFailed: "Impossibile copiare: lo spazio del browser \xE8 pieno o bloccato.",
|
|
2257
|
+
pasteNotAllowed: 'Nulla \xE8 stato incollato: "{uid}" non \xE8 consentito in questa zona.',
|
|
2258
|
+
pasteFull: "Nulla \xE8 stato incollato: la zona non ha spazio per altri {count} blocchi.",
|
|
2259
|
+
pasteUnbalanced: "Nulla \xE8 stato incollato: i blocchi copiati contengono un gruppo incompleto.",
|
|
2260
|
+
rowActionFailed: "Impossibile completare l'azione; il modulo non \xE8 cambiato.",
|
|
2261
|
+
rowActionsTitle: "Azioni dei blocchi",
|
|
2262
|
+
confirmDeleteOption: "Chiedi conferma prima di eliminare un blocco",
|
|
2263
|
+
duplicateOption: 'Mostra "Duplica" su ogni blocco',
|
|
2264
|
+
clipboardOption: 'Mostra "Copia" e "Incolla" (tra pagine)',
|
|
2265
|
+
hiddenBlocks: "Blocchi nascosti sul sito",
|
|
2266
|
+
"hiddenModes.strip": "Rimossi dall'API dei contenuti",
|
|
2267
|
+
"hiddenModes.flag": "Inviati con il flag (decide il frontend)",
|
|
2268
|
+
"hiddenModes.off": "Disattivato (nessun pulsante nascondi)",
|
|
2269
|
+
hiddenBlocksHelp: "L'occhio su ogni blocco lo segna come nascosto sul sito. Rimossi: le letture dell'API dei contenuti (REST, GraphQL) lo omettono, l'admin lo mostra sempre. Flag: viene inviato con l'attributo e decide il frontend.",
|
|
2270
|
+
hiddenAttributeOff: "La configurazione del plugin imposta hiddenAttribute a false: i blocchi non possono essere nascosti."
|
|
1049
2271
|
};
|
|
1050
2272
|
|
|
1051
2273
|
// admin/translations/nl.json
|
|
@@ -1090,10 +2312,11 @@ var nl_default = {
|
|
|
1090
2312
|
"templates.faq": "FAQ",
|
|
1091
2313
|
brokenMedia: "Het gekozen medium bestaat niet meer; de volgende bron wordt gebruikt.",
|
|
1092
2314
|
editor: "Editorvoorkeuren",
|
|
1093
|
-
enabled: "
|
|
1094
|
-
enabledHelp: "Uit
|
|
2315
|
+
enabled: "Blockscene aan",
|
|
2316
|
+
enabledHelp: "Uit zet de hele plugin meteen uit, zonder herstart: elke bewerkweergave is weer native en de groepscontrole bij publiceren stopt. Gebruik dit als er in productie iets misgaat.",
|
|
1095
2317
|
showOpenAll: '"Alle blokken openen" tonen',
|
|
1096
2318
|
showCloseAll: '"Alle blokken sluiten" tonen',
|
|
2319
|
+
showRowThumbnails: "Blokminiaturen in de rijen tonen",
|
|
1097
2320
|
initialState: "Beginstand van de accordeons",
|
|
1098
2321
|
"states.closed": "Alle gesloten",
|
|
1099
2322
|
"states.open": "Alle open",
|
|
@@ -1105,13 +2328,20 @@ var nl_default = {
|
|
|
1105
2328
|
"modes.form": "Velden",
|
|
1106
2329
|
"modes.split": "Velden + pagina",
|
|
1107
2330
|
"modes.preview": "Visuele editor",
|
|
1108
|
-
previewModeHelp: "
|
|
2331
|
+
previewModeHelp: "Elke bewerkweergave opent in deze modus, tenzij het contenttype hieronder een eigen modus instelt. Tijdens het bewerken kan je wisselen; die keuze wordt niet onthouden.",
|
|
2332
|
+
lazyEdit: "Klik om te bewerken",
|
|
2333
|
+
lazyEditors: "Rich-text-editors op aanvraag laden",
|
|
2334
|
+
lazyFields: "Aangepaste velden die op aanvraag laden",
|
|
2335
|
+
lazyEditorsHelp: "De vermelde aangepaste velden tonen een alleen-lezen voorbeeld tot ze worden aangeklikt of focus krijgen, zodat grote pagina's snel openen. Scheid uids met komma's.",
|
|
2336
|
+
lazyFieldsInvalid: "Gebruik maximaal {max} uids van aangepaste velden, zoals plugin::ckeditor5.CKEditor of global::mijn-veld.",
|
|
1109
2337
|
previewV4: "Het paginavoorbeeld bestaat alleen in de Strapi 5-distributie; deze opties hebben geen effect op Strapi 4.",
|
|
1110
2338
|
modeForm: "Velden",
|
|
1111
2339
|
modeSplit: "Velden + pagina",
|
|
1112
2340
|
modePreview: "Visuele editor",
|
|
1113
2341
|
previewPane: "Paginavoorbeeld",
|
|
1114
2342
|
resize: "Voorbeeldpaneel aanpassen",
|
|
2343
|
+
resizeHint: "Sleep om te wijzigen; dubbelklik zet terug op de helft",
|
|
2344
|
+
scrollToHovered: "Naar het gemarkeerde blok scrollen",
|
|
1115
2345
|
previewHelp: "Niet-opgeslagen wijzigingen verschijnen in het voorbeeld. Klik op een blok om het formulier te openen, op een afbeelding voor de Mediabibliotheek, op een tekst om die te bewerken.",
|
|
1116
2346
|
previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
|
|
1117
2347
|
previewFailed: "Het voorbeeld antwoordde niet binnen 15 s. Als de frontend nog laadt, verschijnt het vanzelf; het formulier blijft bruikbaar.",
|
|
@@ -1148,19 +2378,137 @@ var nl_default = {
|
|
|
1148
2378
|
diagInsertClose: 'Ontbrekende sluiting "{expected}" invoegen na rij {n}',
|
|
1149
2379
|
diagStrayHint: "Verwijder de losse markering met de verwijderactie van de rij, of verplaats hem achter een opening.",
|
|
1150
2380
|
modeGroup: "Bewerkmodus",
|
|
2381
|
+
undo: "Ongedaan maken",
|
|
2382
|
+
redo: "Opnieuw",
|
|
2383
|
+
historyGroup: "Bewerkingsgeschiedenis",
|
|
1151
2384
|
saveDisabledHint: "Geen niet-opgeslagen wijzigingen.",
|
|
1152
2385
|
publishDisabledHint: "Publiceren niet beschikbaar: sla eerst op, herstel de fouten in het formulier of controleer uw rechten.",
|
|
1153
2386
|
countAll: "{count} blokken",
|
|
1154
2387
|
countFiltered: "{shown} van {total}",
|
|
1155
|
-
filterCategory: "Filteren op categorie",
|
|
1156
|
-
allCategories: "Alle categorie\xEBn",
|
|
1157
2388
|
showFields: "Velden",
|
|
1158
2389
|
showFieldsHint: "Veldenlijst op elk blok tonen",
|
|
1159
2390
|
columns: "Kolommen",
|
|
1160
2391
|
noPreview: "geen voorbeeld",
|
|
1161
2392
|
"templates.none": "Geen voorbeeld",
|
|
1162
2393
|
noChanges: "Geen niet-opgeslagen wijzigingen",
|
|
1163
|
-
rowPreview: "Voorbeeld van {label} openen"
|
|
2394
|
+
rowPreview: "Voorbeeld van {label} openen",
|
|
2395
|
+
deviceGroup: "Voorbeeldbreedte",
|
|
2396
|
+
"device.fit": "Passend",
|
|
2397
|
+
"device.mobile": "Mobiel",
|
|
2398
|
+
"device.tablet": "Tablet",
|
|
2399
|
+
"device.desktop": "Desktop",
|
|
2400
|
+
contentTypes: "Contenttypes",
|
|
2401
|
+
contentTypesHelp: 'De galerij, accordeons en paginavoorbeeld werken op deze contenttypes (die met een Dynamic Zone). Zet er een uit om de bewerking native te laten. "Opent in" bepaalt hoe elke bewerkweergave van dat type start; tijdens het bewerken kan je nog wisselen.',
|
|
2402
|
+
typeMode: "Opent in",
|
|
2403
|
+
modeDefault: "Standaard ({mode})",
|
|
2404
|
+
blockModalDone: "Klaar",
|
|
2405
|
+
crashed: "Blockscene is hier gestopt door een fout. De native editor blijft werken. Gebeurt het opnieuw, zet Blockscene uit in Settings, Blockscene.",
|
|
2406
|
+
sidebarLabel: "Paginavelden",
|
|
2407
|
+
"nav.all": "Alle",
|
|
2408
|
+
"nav.recent": "Recent gebruikt",
|
|
2409
|
+
"nav.starred": "Favorieten",
|
|
2410
|
+
typologiesTitle: "Typologie\xEBn",
|
|
2411
|
+
collapseSidebar: "Zijbalk inklappen",
|
|
2412
|
+
expandSidebar: "Zijbalk uitklappen",
|
|
2413
|
+
"filters.tags": "Tags",
|
|
2414
|
+
"filters.media": "Media",
|
|
2415
|
+
"filters.content": "Inhoud",
|
|
2416
|
+
clearAll: "Alles wissen",
|
|
2417
|
+
removeFilter: "Filter {name} verwijderen",
|
|
2418
|
+
"typologies.hero": "Hero",
|
|
2419
|
+
"typologies.text": "Tekst",
|
|
2420
|
+
"typologies.media": "Media",
|
|
2421
|
+
"typologies.listing": "Overzicht",
|
|
2422
|
+
"typologies.cards": "Kaarten",
|
|
2423
|
+
"typologies.cta": "Call-to-action",
|
|
2424
|
+
"typologies.form": "Formulier",
|
|
2425
|
+
"typologies.layout": "Lay-out",
|
|
2426
|
+
"facets.image": "Afbeelding",
|
|
2427
|
+
"facets.video": "Video",
|
|
2428
|
+
"facets.gallery": "Galerij",
|
|
2429
|
+
"facets.richtext": "Opgemaakte tekst",
|
|
2430
|
+
"facets.list": "Lijst",
|
|
2431
|
+
"facets.dynamic": "Dynamisch",
|
|
2432
|
+
"facets.form": "Formulier",
|
|
2433
|
+
star: "Als favoriet markeren",
|
|
2434
|
+
unstar: "Uit favorieten verwijderen",
|
|
2435
|
+
quickInsert: "{label} invoegen",
|
|
2436
|
+
insert: "Invoegen",
|
|
2437
|
+
closeDetail: "Details sluiten",
|
|
2438
|
+
typology: "Typologie",
|
|
2439
|
+
typologyAuto: "Automatisch ({name})",
|
|
2440
|
+
tags: "Tags",
|
|
2441
|
+
tagsHelp: "Kommagescheiden, tot 10 tags van 24 tekens. Ze worden een filter in de galerij.",
|
|
2442
|
+
sidebarTitle: "Zijbalk van de visuele editor: {name}",
|
|
2443
|
+
sidebarHelp: "Knoppen aan een rand van de visuele editor. Elke knop opent enkele velden van het document in een lade of een venster.",
|
|
2444
|
+
sidebarPosition: "Positie van de zijbalk",
|
|
2445
|
+
"positions.left": "Links",
|
|
2446
|
+
"positions.right": "Rechts",
|
|
2447
|
+
"positions.bottom": "Onder",
|
|
2448
|
+
sidebarItemLabel: "Label",
|
|
2449
|
+
sidebarIcon: "Pictogram",
|
|
2450
|
+
noIcon: "Geen pictogram",
|
|
2451
|
+
"icons.text": "Tekst",
|
|
2452
|
+
"icons.tag": "Tag",
|
|
2453
|
+
"icons.seo": "SEO",
|
|
2454
|
+
"icons.settings": "Instellingen",
|
|
2455
|
+
"icons.image": "Afbeelding",
|
|
2456
|
+
"icons.link": "Link",
|
|
2457
|
+
"icons.palette": "Palet",
|
|
2458
|
+
"icons.list": "Lijst",
|
|
2459
|
+
"icons.globe": "Wereldbol",
|
|
2460
|
+
"icons.info": "Info",
|
|
2461
|
+
sidebarOpens: "Opent als",
|
|
2462
|
+
"opens.drawer": "Lade",
|
|
2463
|
+
"opens.modal": "Venster",
|
|
2464
|
+
moveUp: "Omhoog",
|
|
2465
|
+
moveDown: "Omlaag",
|
|
2466
|
+
sidebarRemove: "Item verwijderen",
|
|
2467
|
+
sidebarFields: "Velden",
|
|
2468
|
+
sidebarInvalid: "Geef het item een label (maximaal 40 tekens, zonder < of >) en kies minstens \xE9\xE9n veld.",
|
|
2469
|
+
sidebarInvalidSave: "Herstel de hierboven gemarkeerde zijbalkitems voordat je opslaat.",
|
|
2470
|
+
sidebarAdd: "Item toevoegen",
|
|
2471
|
+
sidebarLimit: "Maximaal {max} items.",
|
|
2472
|
+
restoreProject: "Projectstandaarden herstellen",
|
|
2473
|
+
resetAll: "Standaardwaarden herstellen",
|
|
2474
|
+
restoreProjectConfirm: "Alle op deze pagina opgeslagen instellingen verwerpen en teruggaan naar de projectstandaarden uit de code?",
|
|
2475
|
+
resetAllConfirm: "Alle op deze pagina opgeslagen instellingen verwerpen en teruggaan naar de standaardwaarden?",
|
|
2476
|
+
restored: "Standaardwaarden hersteld.",
|
|
2477
|
+
blockPreview: "Livevoorbeeld van het blok",
|
|
2478
|
+
livePreviewFailed: "Livevoorbeeld niet beschikbaar, de afbeelding wordt getoond.",
|
|
2479
|
+
blockPreviewUrl: "URL van blokvoorbeeld",
|
|
2480
|
+
blockPreviewUrlHelp: "Optioneel. Een pagina van uw frontend die \xE9\xE9n blok rendert, groot getoond wanneer op een galerijkaart wordt geklikt, bijv. http://localhost:3026/nl/block-preview/'{name}'/'{variant}'. Plaatshouders: '{uid}', '{name}' (na de punt), '{category}' (voor de punt), '{variant}' (default), '{locale}'. Leeg gebruikt de paginavoorbeeldroute als die er is, anders de afbeelding.",
|
|
2481
|
+
rowActions: "Acties voor {label}",
|
|
2482
|
+
selectBlock: "{label} selecteren",
|
|
2483
|
+
hiddenBadge: "Verborgen",
|
|
2484
|
+
hideBlock: "{label} op de site verbergen",
|
|
2485
|
+
showBlock: "{label} op de site tonen",
|
|
2486
|
+
duplicateBlock: "{label} dupliceren",
|
|
2487
|
+
copyBlock: "{label} kopi\xEBren",
|
|
2488
|
+
confirmDeleteTitle: "Blok verwijderen",
|
|
2489
|
+
confirmDelete: "Blok {name} verwijderen?",
|
|
2490
|
+
confirmDeleteMarker: "Dit is een groepsmarkering: alleen de markering wordt verwijderd, niet de blokken in de groep, en de groep blijft onevenwichtig tot hij hersteld is.",
|
|
2491
|
+
delete: "Verwijderen",
|
|
2492
|
+
selectMode: "Blokken selecteren om te kopi\xEBren",
|
|
2493
|
+
copySelected: "Selectie kopi\xEBren ({count})",
|
|
2494
|
+
paste: "{count, plural, one {# blok} other {# blokken}} plakken",
|
|
2495
|
+
pasted: "{count, plural, one {# blok geplakt} other {# blokken geplakt}}.",
|
|
2496
|
+
copied: "{count, plural, one {# blok gekopieerd} other {# blokken gekopieerd}}. Plak ze op elke pagina van deze site.",
|
|
2497
|
+
copyFailed: "Kopi\xEBren mislukt: de browseropslag is vol of geblokkeerd.",
|
|
2498
|
+
pasteNotAllowed: 'Er is niets geplakt: "{uid}" is niet toegestaan in deze zone.',
|
|
2499
|
+
pasteFull: "Er is niets geplakt: de zone heeft geen ruimte voor nog {count} blokken.",
|
|
2500
|
+
pasteUnbalanced: "Er is niets geplakt: de gekopieerde blokken bevatten een onvolledige groep.",
|
|
2501
|
+
rowActionFailed: "De actie kon niet worden uitgevoerd; het formulier is niet gewijzigd.",
|
|
2502
|
+
rowActionsTitle: "Blokacties",
|
|
2503
|
+
confirmDeleteOption: "Bevestigen voordat een blok wordt verwijderd",
|
|
2504
|
+
duplicateOption: '"Dupliceren" op elk blok tonen',
|
|
2505
|
+
clipboardOption: `"Kopi\xEBren" en "Plakken" tonen (tussen pagina's)`,
|
|
2506
|
+
hiddenBlocks: "Op de site verborgen blokken",
|
|
2507
|
+
"hiddenModes.strip": "Verwijderd uit de content-API",
|
|
2508
|
+
"hiddenModes.flag": "Verzonden met de markering (de frontend beslist)",
|
|
2509
|
+
"hiddenModes.off": "Uit (geen verbergknop)",
|
|
2510
|
+
hiddenBlocksHelp: "Het oog op elk blok markeert het als verborgen op de site. Verwijderd: leesverzoeken van de content-API (REST, GraphQL) laten het weg, de admin toont het altijd. Markering: het wordt met het attribuut verzonden en de frontend beslist.",
|
|
2511
|
+
hiddenAttributeOff: "De pluginconfiguratie zet hiddenAttribute op false: blokken kunnen niet verborgen worden."
|
|
1164
2512
|
};
|
|
1165
2513
|
|
|
1166
2514
|
// admin/messages.ts
|
|
@@ -1184,12 +2532,12 @@ function useMessages() {
|
|
|
1184
2532
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1185
2533
|
var ATTR = "data-blockscene-row-thumb";
|
|
1186
2534
|
function useAnchors(zones, onOpen) {
|
|
1187
|
-
const [anchors, setAnchors] =
|
|
1188
|
-
const open =
|
|
2535
|
+
const [anchors, setAnchors] = React2.useState([]);
|
|
2536
|
+
const open = React2.useRef(onOpen);
|
|
1189
2537
|
open.current = onOpen;
|
|
1190
|
-
const latest =
|
|
2538
|
+
const latest = React2.useRef(zones);
|
|
1191
2539
|
latest.current = zones;
|
|
1192
|
-
const sync =
|
|
2540
|
+
const sync = React2.useRef(() => {
|
|
1193
2541
|
});
|
|
1194
2542
|
sync.current = () => {
|
|
1195
2543
|
const next = [];
|
|
@@ -1235,22 +2583,22 @@ function useAnchors(zones, onOpen) {
|
|
|
1235
2583
|
(prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.uid === next[i].uid) ? prev : next
|
|
1236
2584
|
);
|
|
1237
2585
|
};
|
|
1238
|
-
|
|
2586
|
+
React2.useEffect(() => {
|
|
1239
2587
|
sync.current();
|
|
1240
2588
|
});
|
|
1241
|
-
|
|
1242
|
-
let
|
|
2589
|
+
React2.useEffect(() => {
|
|
2590
|
+
let frame2 = 0;
|
|
1243
2591
|
const observer = new MutationObserver(() => {
|
|
1244
|
-
if (
|
|
1245
|
-
|
|
1246
|
-
|
|
2592
|
+
if (frame2) return;
|
|
2593
|
+
frame2 = requestAnimationFrame(() => {
|
|
2594
|
+
frame2 = 0;
|
|
1247
2595
|
sync.current();
|
|
1248
2596
|
});
|
|
1249
2597
|
});
|
|
1250
2598
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
1251
2599
|
return () => {
|
|
1252
2600
|
observer.disconnect();
|
|
1253
|
-
cancelAnimationFrame(
|
|
2601
|
+
cancelAnimationFrame(frame2);
|
|
1254
2602
|
for (const el of document.querySelectorAll(`[${ATTR}]`)) el.remove();
|
|
1255
2603
|
};
|
|
1256
2604
|
}, []);
|
|
@@ -1258,13 +2606,13 @@ function useAnchors(zones, onOpen) {
|
|
|
1258
2606
|
}
|
|
1259
2607
|
function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
|
|
1260
2608
|
const t = useMessages();
|
|
1261
|
-
const [resolved, setResolved] =
|
|
1262
|
-
const [open, setOpen] =
|
|
2609
|
+
const [resolved, setResolved] = React2.useState({});
|
|
2610
|
+
const [open, setOpen] = React2.useState(null);
|
|
1263
2611
|
const anchors = useAnchors(zones, (uid) => setOpen(uid));
|
|
1264
2612
|
const candidates = (uid) => candidatesFor(uid, catalog?.components?.[uid] || {}, catalog || {});
|
|
1265
2613
|
const label = (uid) => catalog?.components?.[uid]?.label || components?.[uid]?.info?.displayName || uid;
|
|
1266
2614
|
const srcOf = (uid) => candidates(uid)[resolved[uid] ?? -1] || "";
|
|
1267
|
-
|
|
2615
|
+
React2.useEffect(() => {
|
|
1268
2616
|
for (const { el, uid } of anchors) {
|
|
1269
2617
|
if (srcOf(uid)) {
|
|
1270
2618
|
el.setAttribute("role", "button");
|
|
@@ -1332,9 +2680,469 @@ function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
|
|
|
1332
2680
|
] });
|
|
1333
2681
|
}
|
|
1334
2682
|
|
|
1335
|
-
// admin/
|
|
2683
|
+
// admin/RowActions.tsx
|
|
2684
|
+
var React3 = __toESM(require("react"));
|
|
2685
|
+
var import_react_dom2 = require("react-dom");
|
|
2686
|
+
var import_styled_components2 = __toESM(require("styled-components"));
|
|
2687
|
+
var import_design_system = require("@strapi/design-system");
|
|
2688
|
+
|
|
2689
|
+
// admin/rows.mjs
|
|
2690
|
+
var import_fractional_indexing2 = require("fractional-indexing");
|
|
2691
|
+
var import_groups2 = __toESM(require_groups(), 1);
|
|
2692
|
+
var actionRange = (rows, index, groups) => groups && (0, import_groups2.isOpener)(rows[index], groups) ? (0, import_groups2.groupRange)(rows, index, groups) : [index, index];
|
|
2693
|
+
function expandSelection(rows, indexes, groups) {
|
|
2694
|
+
const out = /* @__PURE__ */ new Set();
|
|
2695
|
+
for (const index of indexes) {
|
|
2696
|
+
if (!rows[index]) continue;
|
|
2697
|
+
const [start, end] = actionRange(rows, index, groups);
|
|
2698
|
+
for (let i = start; i <= end; i++) out.add(i);
|
|
2699
|
+
}
|
|
2700
|
+
return [...out].sort((a, b) => a - b);
|
|
2701
|
+
}
|
|
2702
|
+
var canAct = (row, groups) => !(groups && (0, import_groups2.isClose)(row, groups));
|
|
2703
|
+
var isGroupMarker = (row, groups) => Boolean(groups) && ((0, import_groups2.isOpener)(row, groups) || (0, import_groups2.isClose)(row, groups));
|
|
2704
|
+
var copy = (value) => {
|
|
2705
|
+
try {
|
|
2706
|
+
return structuredClone(value);
|
|
2707
|
+
} catch {
|
|
2708
|
+
return JSON.parse(JSON.stringify(value));
|
|
2709
|
+
}
|
|
2710
|
+
};
|
|
2711
|
+
function cloneRow(row, components, { relation } = {}) {
|
|
2712
|
+
const walk = (value, schema, path) => {
|
|
2713
|
+
const out = {};
|
|
2714
|
+
for (const [key, item] of Object.entries(value || {})) {
|
|
2715
|
+
if (key === "id" || key === "documentId") continue;
|
|
2716
|
+
const attr = schema?.attributes?.[key];
|
|
2717
|
+
if (attr?.type === "component" && item) {
|
|
2718
|
+
const child = components?.[attr.component];
|
|
2719
|
+
out[key] = attr.repeatable ? (Array.isArray(item) ? item : []).map((entry, i) => walk(entry, child, [...path, key, i])) : walk(item, child, [...path, key]);
|
|
2720
|
+
} else if (attr?.type === "relation" && relation) out[key] = relation(item, attr, [...path, key]);
|
|
2721
|
+
else out[key] = copy(item);
|
|
2722
|
+
}
|
|
2723
|
+
return out;
|
|
2724
|
+
};
|
|
2725
|
+
return walk(row, components?.[row?.__component], []);
|
|
2726
|
+
}
|
|
2727
|
+
function integerKeys(rows, n) {
|
|
2728
|
+
const max = Math.max(-1, ...rows.map((row) => Number(row?.__temp_key__)).filter(Number.isFinite));
|
|
2729
|
+
return Array.from({ length: n }, (_, i) => max + 1 + i);
|
|
2730
|
+
}
|
|
2731
|
+
var insertRows = (rows, at, items, keys) => [
|
|
2732
|
+
...rows.slice(0, at),
|
|
2733
|
+
...items.map((item, i) => ({ ...item, __temp_key__: keys[i] })),
|
|
2734
|
+
...rows.slice(at)
|
|
2735
|
+
];
|
|
2736
|
+
function setHidden(rows, index, groups, name, value) {
|
|
2737
|
+
const [start, end] = actionRange(rows, index, groups);
|
|
2738
|
+
return rows.map((row, i) => i >= start && i <= end ? { ...row, [name]: value } : row);
|
|
2739
|
+
}
|
|
2740
|
+
var CLIPBOARD_KEY = "blockscene:clipboard:v1";
|
|
2741
|
+
var MAX_ROWS = 200;
|
|
2742
|
+
function readClip(storage3) {
|
|
2743
|
+
try {
|
|
2744
|
+
const clip = JSON.parse(storage3?.getItem(CLIPBOARD_KEY) || "null");
|
|
2745
|
+
return clip && clip.v === 1 && Array.isArray(clip.rows) && clip.rows.length > 0 && clip.rows.length <= MAX_ROWS && clip.rows.every((row) => row && typeof row.__component === "string") ? clip : null;
|
|
2746
|
+
} catch {
|
|
2747
|
+
return null;
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
function writeClip(storage3, { rows, model, locale, zone }) {
|
|
2751
|
+
try {
|
|
2752
|
+
if (!rows.length || rows.length > MAX_ROWS) return false;
|
|
2753
|
+
storage3.setItem(CLIPBOARD_KEY, JSON.stringify({ v: 1, model, locale: locale || "", zone, at: Date.now(), rows }));
|
|
2754
|
+
return true;
|
|
2755
|
+
} catch {
|
|
2756
|
+
return false;
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
function pasteProblem(clip, zone, rows, components, groups) {
|
|
2760
|
+
if (!clip?.rows?.length) return { code: "empty" };
|
|
2761
|
+
const bad = clip.rows.find((row) => !zone?.components?.includes(row.__component) || !components?.[row.__component]);
|
|
2762
|
+
if (bad) return { code: "notAllowed", uid: bad.__component };
|
|
2763
|
+
if ((rows?.length || 0) + clip.rows.length > (zone.max ?? Infinity)) return { code: "full" };
|
|
2764
|
+
if (groups && (0, import_groups2.validateGroups)(clip.rows, groups).length) return { code: "unbalanced" };
|
|
2765
|
+
return null;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
// admin/icons.tsx
|
|
2769
|
+
var import_styled_components = __toESM(require("styled-components"));
|
|
1336
2770
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1337
|
-
var
|
|
2771
|
+
var PATHS = {
|
|
2772
|
+
text: "M5 6V4h14v2M12 4v16M9 20h6",
|
|
2773
|
+
tag: "M3 12V4h8l10 10-8 8L3 12zM7.5 7.5h.01",
|
|
2774
|
+
seo: "M11 4a7 7 0 1 0 0 14 7 7 0 0 0 0-14zM20 20l-4-4",
|
|
2775
|
+
settings: "M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6zM12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1",
|
|
2776
|
+
image: "M4 5h16v14H4zM4 16l5-5 4 4 3-3 4 4M15.5 9.5h.01",
|
|
2777
|
+
link: "M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1",
|
|
2778
|
+
palette: "M12 3a9 9 0 1 0 0 18c1 0 1.5-.7 1.5-1.5 0-1.2-1-1.5-1-2.5s.7-1.5 1.5-1.5H16a5 5 0 0 0 5-5c0-4.1-4-7.5-9-7.5zM7.5 11h.01M10 7h.01M15 7h.01",
|
|
2779
|
+
list: "M9 6h11M9 12h11M9 18h11M4.5 6h.01M4.5 12h.01M4.5 18h.01",
|
|
2780
|
+
globe: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM3 12h18M12 3c2.5 2.5 3.7 5.5 3.7 9s-1.2 6.5-3.7 9c-2.5-2.5-3.7-5.5-3.7-9S9.5 5.5 12 3z",
|
|
2781
|
+
info: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 11v6M12 7.5h.01",
|
|
2782
|
+
// Toolbar icons (not offered for sidebar items).
|
|
2783
|
+
split: "M3 4h18v16H3zM12 4v16",
|
|
2784
|
+
eye: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12zM12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z",
|
|
2785
|
+
fit: "M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5",
|
|
2786
|
+
mobile: "M8 3h8v18H8zM11.5 18h1",
|
|
2787
|
+
tablet: "M5 3h14v18H5zM11.5 18h1",
|
|
2788
|
+
desktop: "M3 4h18v12H3zM8 20h8M12 16v4",
|
|
2789
|
+
expand: "M7 7l5 5 5-5M7 13l5 5 5-5",
|
|
2790
|
+
collapse: "M7 17l5-5 5 5M7 11l5-5 5 5",
|
|
2791
|
+
undo: "M9 14L4 9l5-5M4 9h10.5a5.5 5.5 0 0 1 0 11H11",
|
|
2792
|
+
redo: "M15 14l5-5-5-5M20 9H9.5a5.5 5.5 0 0 0 0 11H13",
|
|
2793
|
+
// Gallery: navigation, card actions and typologies (text, media, listing and cta reuse text, image, list and link).
|
|
2794
|
+
grid: "M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z",
|
|
2795
|
+
clock: "M12 3a9 9 0 1 0 0 18 9 9 0 0 0 0-18zM12 7v5l3 2",
|
|
2796
|
+
star: "M12 3l2.8 5.7 6.2.9-4.5 4.4 1.1 6.2L12 17.3 6.4 20.2l1.1-6.2L3 9.6l6.2-.9L12 3z",
|
|
2797
|
+
plus: "M12 5v14M5 12h14",
|
|
2798
|
+
close: "M6 6l12 12M18 6L6 18",
|
|
2799
|
+
chevron: "M6 9l6 6 6-6",
|
|
2800
|
+
// Settings: sidebar item order.
|
|
2801
|
+
up: "M12 19V5M6 11l6-6 6 6",
|
|
2802
|
+
down: "M12 5v14M6 13l6 6 6-6",
|
|
2803
|
+
sidebar: "M3 4h18v16H3zM9 4v16",
|
|
2804
|
+
hero: "M3 4h18v10H3zM7 18h10M9 21h6",
|
|
2805
|
+
cards: "M3 5h8v14H3zM13 5h8v14h-8z",
|
|
2806
|
+
form: "M4 4h16v16H4zM8 9h8M8 13h8M8 17h4",
|
|
2807
|
+
layout: "M3 4h18v16H3zM3 10h18M12 10v10",
|
|
2808
|
+
// Row actions.
|
|
2809
|
+
eyeOff: "M3 3l18 18M10.6 5.1A10 10 0 0 1 12 5c6.5 0 10 7 10 7a17 17 0 0 1-3.1 4M6.6 6.6C3.9 8.4 2 12 2 12s3.5 7 10 7c1.9 0 3.6-.6 5-1.5M9.9 9.9a3 3 0 0 0 4.2 4.2",
|
|
2810
|
+
duplicate: "M8 8h12v12H8zM4 16V4h12",
|
|
2811
|
+
clipboard: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2",
|
|
2812
|
+
paste: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2M12 10v7M9 14l3 3 3-3",
|
|
2813
|
+
select: "M4 4h16v16H4zM8 12l3 3 5-6"
|
|
2814
|
+
};
|
|
2815
|
+
function Icon({ name, size = 18, filled }) {
|
|
2816
|
+
const d = PATHS[name];
|
|
2817
|
+
if (!d) return null;
|
|
2818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: filled ? "currentColor" : "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d }) });
|
|
2819
|
+
}
|
|
2820
|
+
var ToolButton = import_styled_components.default.button`
|
|
2821
|
+
display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0;
|
|
2822
|
+
border: 1px solid ${({ theme }) => theme.colors.neutral200}; border-radius: 4px; cursor: pointer;
|
|
2823
|
+
color: ${({ theme, $active }) => $active ? theme.colors.primary600 : theme.colors.neutral700};
|
|
2824
|
+
background: ${({ theme, $active }) => $active ? theme.colors.primary100 : theme.colors.neutral0};
|
|
2825
|
+
&:hover:not(:disabled) { background: ${({ theme, $active }) => $active ? theme.colors.primary100 : theme.colors.neutral100}; }
|
|
2826
|
+
&:disabled { opacity: 0.4; cursor: default; }
|
|
2827
|
+
&:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 1px; }
|
|
2828
|
+
`;
|
|
2829
|
+
var Tool = ({ icon, label, active, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolButton, { type: "button", "aria-label": label, title: label, $active: active, ...active !== void 0 ? { "aria-pressed": active } : {}, ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { name: icon }) });
|
|
2830
|
+
|
|
2831
|
+
// admin/RowActions.tsx
|
|
2832
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2833
|
+
var ATTR2 = "data-blockscene-row-actions";
|
|
2834
|
+
var HIDDEN_ATTR = "data-blockscene-hidden";
|
|
2835
|
+
var CLIP_EVENT = "blockscene:clipboard";
|
|
2836
|
+
var storage = () => {
|
|
2837
|
+
try {
|
|
2838
|
+
return window.localStorage;
|
|
2839
|
+
} catch {
|
|
2840
|
+
return null;
|
|
2841
|
+
}
|
|
2842
|
+
};
|
|
2843
|
+
function useClipboard() {
|
|
2844
|
+
const [clip, setClip] = React3.useState(() => readClip(storage()));
|
|
2845
|
+
React3.useEffect(() => {
|
|
2846
|
+
const sync = (event) => {
|
|
2847
|
+
if (!event?.key || event.key === CLIPBOARD_KEY) setClip(readClip(storage()));
|
|
2848
|
+
};
|
|
2849
|
+
window.addEventListener("storage", sync);
|
|
2850
|
+
window.addEventListener(CLIP_EVENT, sync);
|
|
2851
|
+
return () => {
|
|
2852
|
+
window.removeEventListener("storage", sync);
|
|
2853
|
+
window.removeEventListener(CLIP_EVENT, sync);
|
|
2854
|
+
};
|
|
2855
|
+
}, []);
|
|
2856
|
+
return clip;
|
|
2857
|
+
}
|
|
2858
|
+
var storeClip = (data) => {
|
|
2859
|
+
const ok = writeClip(storage(), data);
|
|
2860
|
+
if (ok) window.dispatchEvent(new Event(CLIP_EVENT));
|
|
2861
|
+
return ok;
|
|
2862
|
+
};
|
|
2863
|
+
function pasteInto(form, zone, clip, components, groups, t, at) {
|
|
2864
|
+
const rows = form.rows(zone.name);
|
|
2865
|
+
const problem = pasteProblem(clip, zone, rows, components, groups);
|
|
2866
|
+
if (problem) {
|
|
2867
|
+
form.notify("warning", t.f(
|
|
2868
|
+
problem.code === "notAllowed" ? "pasteNotAllowed" : problem.code === "full" ? "pasteFull" : "pasteUnbalanced",
|
|
2869
|
+
{ uid: problem.uid || "", count: clip?.rows?.length || 0 }
|
|
2870
|
+
));
|
|
2871
|
+
return false;
|
|
2872
|
+
}
|
|
2873
|
+
const index = at ?? rows.length;
|
|
2874
|
+
form.setRows(zone.name, insertRows(rows, index, clip.rows, form.keys(rows, index, clip.rows.length)));
|
|
2875
|
+
form.notify("success", t.f("pasted", { count: clip.rows.length }));
|
|
2876
|
+
return true;
|
|
2877
|
+
}
|
|
2878
|
+
var actionsOf = (toggle) => toggle.nextElementSibling;
|
|
2879
|
+
var trashOf = (toggle) => [...actionsOf(toggle)?.querySelectorAll("button") || []].find((b) => !b.closest(`[${ATTR2}]`)) || null;
|
|
2880
|
+
function useAnchors2(zones, enabled) {
|
|
2881
|
+
const [anchors, setAnchors] = React3.useState([]);
|
|
2882
|
+
const latest = React3.useRef(zones);
|
|
2883
|
+
latest.current = zones;
|
|
2884
|
+
const sync = React3.useRef(() => {
|
|
2885
|
+
});
|
|
2886
|
+
sync.current = () => {
|
|
2887
|
+
const next = [];
|
|
2888
|
+
if (enabled)
|
|
2889
|
+
for (const zone of latest.current) {
|
|
2890
|
+
const list = zone.count ? findZoneList(zone.label) : null;
|
|
2891
|
+
if (!list) continue;
|
|
2892
|
+
toggles(list).forEach((toggle, index) => {
|
|
2893
|
+
const trash = trashOf(toggle);
|
|
2894
|
+
if (!trash || index >= zone.count) return;
|
|
2895
|
+
const holder = trash.parentElement !== actionsOf(toggle) && trash.parentElement?.children.length === 1 ? trash.parentElement : trash;
|
|
2896
|
+
let el = holder.parentElement?.querySelector(`:scope > [${ATTR2}]`);
|
|
2897
|
+
if (!el) {
|
|
2898
|
+
el = document.createElement("span");
|
|
2899
|
+
el.setAttribute(ATTR2, "");
|
|
2900
|
+
el.style.cssText = "display:inline-flex;align-items:center";
|
|
2901
|
+
holder.parentElement?.insertBefore(el, holder);
|
|
2902
|
+
}
|
|
2903
|
+
next.push({ el, zone: zone.name, index });
|
|
2904
|
+
});
|
|
2905
|
+
}
|
|
2906
|
+
for (const el of document.querySelectorAll(`[${ATTR2}]`)) if (!next.some((a) => a.el === el)) el.remove();
|
|
2907
|
+
setAnchors(
|
|
2908
|
+
(prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.zone === next[i].zone && a.index === next[i].index) ? prev : next
|
|
2909
|
+
);
|
|
2910
|
+
};
|
|
2911
|
+
React3.useEffect(() => {
|
|
2912
|
+
sync.current();
|
|
2913
|
+
});
|
|
2914
|
+
React3.useEffect(() => {
|
|
2915
|
+
let frame2 = 0;
|
|
2916
|
+
const observer = new MutationObserver(() => {
|
|
2917
|
+
if (!frame2) frame2 = requestAnimationFrame(() => {
|
|
2918
|
+
frame2 = 0;
|
|
2919
|
+
sync.current();
|
|
2920
|
+
});
|
|
2921
|
+
});
|
|
2922
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
2923
|
+
return () => {
|
|
2924
|
+
observer.disconnect();
|
|
2925
|
+
cancelAnimationFrame(frame2);
|
|
2926
|
+
for (const el of document.querySelectorAll(`[${ATTR2}]`)) el.remove();
|
|
2927
|
+
for (const el of document.querySelectorAll(`[${HIDDEN_ATTR}]`)) el.removeAttribute(HIDDEN_ATTR);
|
|
2928
|
+
};
|
|
2929
|
+
}, []);
|
|
2930
|
+
return anchors;
|
|
2931
|
+
}
|
|
2932
|
+
function useRowActions({ zones, components, catalog, form }) {
|
|
2933
|
+
const t = useMessages();
|
|
2934
|
+
const clip = useClipboard();
|
|
2935
|
+
const [selection, setSelection] = React3.useState(null);
|
|
2936
|
+
const [busy, setBusy] = React3.useState(false);
|
|
2937
|
+
if (!form) return null;
|
|
2938
|
+
const editor = catalog?.editor || {};
|
|
2939
|
+
const groups = catalog?.groups || null;
|
|
2940
|
+
const hiddenName = editor.hiddenBlocks !== "off" ? catalog?.hiddenAttribute || null : null;
|
|
2941
|
+
const zoneOf = (name) => zones.find((z) => z.name === name);
|
|
2942
|
+
const labelOf = (row) => catalog?.components?.[row?.__component]?.label || components?.[row?.__component]?.info?.displayName || row?.__component || "";
|
|
2943
|
+
const run = async (fn) => {
|
|
2944
|
+
if (busy) return;
|
|
2945
|
+
setBusy(true);
|
|
2946
|
+
try {
|
|
2947
|
+
await fn();
|
|
2948
|
+
} catch {
|
|
2949
|
+
form.notify("warning", t.rowActionFailed);
|
|
2950
|
+
} finally {
|
|
2951
|
+
setBusy(false);
|
|
2952
|
+
}
|
|
2953
|
+
};
|
|
2954
|
+
const duplicate = (zoneName, index) => run(async () => {
|
|
2955
|
+
const zone = zoneOf(zoneName);
|
|
2956
|
+
const rows = form.rows(zoneName);
|
|
2957
|
+
const key = blockKey(rows[index]);
|
|
2958
|
+
const [start, end] = actionRange(rows, index, groups);
|
|
2959
|
+
if (rows.length + end - start + 1 > (zone?.max ?? Infinity)) return form.notify("warning", t.zoneFull);
|
|
2960
|
+
const items = await form.prepare(rows.slice(start, end + 1));
|
|
2961
|
+
const now = form.rows(zoneName);
|
|
2962
|
+
const at = now.findIndex((row) => blockKey(row) === key);
|
|
2963
|
+
if (at < 0) return;
|
|
2964
|
+
const after = actionRange(now, at, groups)[1] + 1;
|
|
2965
|
+
form.setRows(zoneName, insertRows(now, after, items, form.keys(now, after, items.length)));
|
|
2966
|
+
});
|
|
2967
|
+
const copy2 = (zoneName, keys) => run(async () => {
|
|
2968
|
+
const rows = form.rows(zoneName);
|
|
2969
|
+
const indexes = expandSelection(rows, keys.map((key) => rows.findIndex((row) => blockKey(row) === key)), groups);
|
|
2970
|
+
if (!indexes.length) return;
|
|
2971
|
+
const items = await form.prepare(indexes.map((i) => rows[i]));
|
|
2972
|
+
if (!storeClip({ rows: items, model: form.model, locale: form.locale, zone: zoneName })) return form.notify("warning", t.copyFailed);
|
|
2973
|
+
setSelection(null);
|
|
2974
|
+
form.notify("success", t.f("copied", { count: items.length }));
|
|
2975
|
+
});
|
|
2976
|
+
const toggleHidden = (zoneName, index) => {
|
|
2977
|
+
const rows = form.rows(zoneName);
|
|
2978
|
+
if (hiddenName) form.setRows(zoneName, setHidden(rows, index, groups, hiddenName, rows[index]?.[hiddenName] !== true));
|
|
2979
|
+
};
|
|
2980
|
+
const paste = (zoneName, at) => pasteInto(form, zoneOf(zoneName), clip, components, groups, t, at);
|
|
2981
|
+
return { t, editor, groups, hiddenName, clip, selection, setSelection, busy, form, labelOf, duplicate, copy: copy2, toggleHidden, paste, isMarker: (row) => isGroupMarker(row, groups) };
|
|
2982
|
+
}
|
|
2983
|
+
var RowButton = import_styled_components2.default.button`
|
|
2984
|
+
display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border: 0;
|
|
2985
|
+
border-radius: 4px; cursor: pointer; background: transparent;
|
|
2986
|
+
color: ${({ theme, $on }) => $on ? theme.colors.warning600 : theme.colors.neutral500};
|
|
2987
|
+
&:hover:not(:disabled) { background: ${({ theme }) => theme.colors.neutral100}; color: ${({ theme }) => theme.colors.neutral800}; }
|
|
2988
|
+
&:disabled { opacity: 0.4; cursor: default; }
|
|
2989
|
+
&:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: -2px; }
|
|
2990
|
+
`;
|
|
2991
|
+
var HiddenBadge = import_styled_components2.default.span`
|
|
2992
|
+
margin-right: 4px; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; line-height: 16px;
|
|
2993
|
+
text-transform: uppercase; letter-spacing: 0.04em;
|
|
2994
|
+
color: ${({ theme }) => theme.colors.warning700}; background: ${({ theme }) => theme.colors.warning100};
|
|
2995
|
+
`;
|
|
2996
|
+
function RowActions({ zones, actions, Modal: Modal2 }) {
|
|
2997
|
+
const a = actions;
|
|
2998
|
+
const e = a?.editor || {};
|
|
2999
|
+
const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection));
|
|
3000
|
+
const [confirm, setConfirm] = React3.useState(null);
|
|
3001
|
+
const bypass = React3.useRef(false);
|
|
3002
|
+
const latest = React3.useRef({ zones, a });
|
|
3003
|
+
latest.current = { zones, a };
|
|
3004
|
+
React3.useEffect(() => {
|
|
3005
|
+
if (!a || e.confirmDelete === false) return;
|
|
3006
|
+
const onClick = (event) => {
|
|
3007
|
+
const button = event.target?.closest?.("button");
|
|
3008
|
+
if (!button || bypass.current) return;
|
|
3009
|
+
for (const zone of latest.current.zones) {
|
|
3010
|
+
const list = findZoneList(zone.label);
|
|
3011
|
+
if (!list?.contains(button)) continue;
|
|
3012
|
+
const headers = toggles(list);
|
|
3013
|
+
const index = headers.findIndex((toggle) => trashOf(toggle) === button);
|
|
3014
|
+
if (index < 0) return;
|
|
3015
|
+
event.preventDefault();
|
|
3016
|
+
event.stopPropagation();
|
|
3017
|
+
const row = latest.current.a?.form.rows(zone.name)[index];
|
|
3018
|
+
setConfirm({ button, label: headers[index].textContent?.trim() || latest.current.a?.labelOf(row), marker: Boolean(latest.current.a?.isMarker(row)) });
|
|
3019
|
+
return;
|
|
3020
|
+
}
|
|
3021
|
+
};
|
|
3022
|
+
document.addEventListener("click", onClick, true);
|
|
3023
|
+
return () => document.removeEventListener("click", onClick, true);
|
|
3024
|
+
}, [Boolean(a), e.confirmDelete]);
|
|
3025
|
+
React3.useEffect(() => {
|
|
3026
|
+
if (!a) return;
|
|
3027
|
+
for (const { el, zone, index } of anchors) {
|
|
3028
|
+
const li = el.closest("li");
|
|
3029
|
+
const hidden = Boolean(a.hiddenName) && a.form.rows(zone)[index]?.[a.hiddenName] === true;
|
|
3030
|
+
if (li) hidden ? li.setAttribute(HIDDEN_ATTR, "") : li.removeAttribute(HIDDEN_ATTR);
|
|
3031
|
+
}
|
|
3032
|
+
});
|
|
3033
|
+
if (!a) return null;
|
|
3034
|
+
const { t } = a;
|
|
3035
|
+
const confirmDelete = () => {
|
|
3036
|
+
const target = confirm?.button;
|
|
3037
|
+
setConfirm(null);
|
|
3038
|
+
if (!target?.isConnected) return;
|
|
3039
|
+
bypass.current = true;
|
|
3040
|
+
try {
|
|
3041
|
+
target.click();
|
|
3042
|
+
} finally {
|
|
3043
|
+
bypass.current = false;
|
|
3044
|
+
}
|
|
3045
|
+
};
|
|
3046
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3047
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `li[${HIDDEN_ATTR}] button[aria-expanded] { opacity: 0.5; }` }),
|
|
3048
|
+
anchors.map(({ el, zone, index }) => {
|
|
3049
|
+
const row = a.form.rows(zone)[index];
|
|
3050
|
+
if (!row) return null;
|
|
3051
|
+
const label = a.labelOf(row);
|
|
3052
|
+
const acts = canAct(row, a.groups);
|
|
3053
|
+
const hidden = Boolean(a.hiddenName) && row[a.hiddenName] === true;
|
|
3054
|
+
const key = blockKey(row) || "";
|
|
3055
|
+
const selecting = a.selection?.zone === zone;
|
|
3056
|
+
return (0, import_react_dom2.createPortal)(
|
|
3057
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { gap: 0, alignItems: "center", "data-testid": `row-actions-${zone}-${index}`, role: "group", "aria-label": t.f("rowActions", { label }), children: [
|
|
3058
|
+
selecting && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3059
|
+
"input",
|
|
3060
|
+
{
|
|
3061
|
+
type: "checkbox",
|
|
3062
|
+
"aria-label": t.f("selectBlock", { label }),
|
|
3063
|
+
"data-testid": `row-select-${zone}-${index}`,
|
|
3064
|
+
style: { margin: "0 8px", width: 16, height: 16 },
|
|
3065
|
+
checked: a.selection.keys.includes(key),
|
|
3066
|
+
onChange: (event) => a.setSelection({ zone, keys: event.target.checked ? [...a.selection.keys, key] : a.selection.keys.filter((k) => k !== key) })
|
|
3067
|
+
}
|
|
3068
|
+
),
|
|
3069
|
+
hidden && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HiddenBadge, { "data-testid": `row-hidden-${zone}-${index}`, children: t.hiddenBadge }),
|
|
3070
|
+
a.hiddenName && (acts || hidden) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3071
|
+
RowButton,
|
|
3072
|
+
{
|
|
3073
|
+
type: "button",
|
|
3074
|
+
$on: hidden,
|
|
3075
|
+
"aria-pressed": hidden,
|
|
3076
|
+
title: t.f(hidden ? "showBlock" : "hideBlock", { label }),
|
|
3077
|
+
"aria-label": t.f(hidden ? "showBlock" : "hideBlock", { label }),
|
|
3078
|
+
"data-testid": `row-hide-${zone}-${index}`,
|
|
3079
|
+
onClick: () => a.toggleHidden(zone, index),
|
|
3080
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: hidden ? "eyeOff" : "eye" })
|
|
3081
|
+
}
|
|
3082
|
+
),
|
|
3083
|
+
e.duplicate !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3084
|
+
RowButton,
|
|
3085
|
+
{
|
|
3086
|
+
type: "button",
|
|
3087
|
+
disabled: a.busy,
|
|
3088
|
+
title: t.f("duplicateBlock", { label }),
|
|
3089
|
+
"aria-label": t.f("duplicateBlock", { label }),
|
|
3090
|
+
"data-testid": `row-duplicate-${zone}-${index}`,
|
|
3091
|
+
onClick: () => a.duplicate(zone, index),
|
|
3092
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "duplicate" })
|
|
3093
|
+
}
|
|
3094
|
+
),
|
|
3095
|
+
e.clipboard !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3096
|
+
RowButton,
|
|
3097
|
+
{
|
|
3098
|
+
type: "button",
|
|
3099
|
+
disabled: a.busy,
|
|
3100
|
+
title: t.f("copyBlock", { label }),
|
|
3101
|
+
"aria-label": t.f("copyBlock", { label }),
|
|
3102
|
+
"data-testid": `row-copy-${zone}-${index}`,
|
|
3103
|
+
onClick: () => a.copy(zone, [key]),
|
|
3104
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "clipboard" })
|
|
3105
|
+
}
|
|
3106
|
+
)
|
|
3107
|
+
] }),
|
|
3108
|
+
el,
|
|
3109
|
+
`${zone}:${index}`
|
|
3110
|
+
);
|
|
3111
|
+
}),
|
|
3112
|
+
confirm && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
|
|
3113
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
|
|
3114
|
+
confirm.marker && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
|
|
3115
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { gap: 2, justifyContent: "flex-end", children: [
|
|
3116
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { variant: "tertiary", onClick: () => setConfirm(null), "data-testid": "row-confirm-cancel", children: t.cancel }),
|
|
3117
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { variant: "danger", onClick: confirmDelete, "data-testid": "row-confirm-ok", children: t.delete })
|
|
3118
|
+
] })
|
|
3119
|
+
] }) })
|
|
3120
|
+
] });
|
|
3121
|
+
}
|
|
3122
|
+
function ZoneRowTools({ zone, actions: a }) {
|
|
3123
|
+
if (!a || a.editor.clipboard === false) return null;
|
|
3124
|
+
const { t } = a;
|
|
3125
|
+
const selecting = a.selection?.zone === zone.name;
|
|
3126
|
+
const count = selecting ? a.selection.keys.length : 0;
|
|
3127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
3128
|
+
zone.count > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3129
|
+
Tool,
|
|
3130
|
+
{
|
|
3131
|
+
icon: "select",
|
|
3132
|
+
label: t.selectMode,
|
|
3133
|
+
active: selecting,
|
|
3134
|
+
"data-testid": `zone-select-${zone.name}`,
|
|
3135
|
+
onClick: () => a.setSelection(selecting ? null : { zone: zone.name, keys: [] })
|
|
3136
|
+
}
|
|
3137
|
+
),
|
|
3138
|
+
selecting && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { size: "S", variant: "secondary", disabled: !count || a.busy, onClick: () => a.copy(zone.name, a.selection.keys), "data-testid": `zone-copy-${zone.name}`, children: t.f("copySelected", { count }) }),
|
|
3139
|
+
a.clip && !zone.full && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { size: "S", variant: "secondary", startIcon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "paste", size: 14 }), onClick: () => a.paste(zone.name), "data-testid": `zone-paste-${zone.name}`, children: t.f("paste", { count: a.clip.rows.length }) })
|
|
3140
|
+
] });
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
// admin/Gallery.tsx
|
|
3144
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3145
|
+
var Columns = import_styled_components3.default.div`
|
|
1338
3146
|
column-count: ${({ $columns }) => $columns};
|
|
1339
3147
|
column-gap: 12px;
|
|
1340
3148
|
> * {
|
|
@@ -1343,14 +3151,15 @@ var Columns = import_styled_components.default.div`
|
|
|
1343
3151
|
margin-bottom: 12px;
|
|
1344
3152
|
}
|
|
1345
3153
|
`;
|
|
1346
|
-
var Tile =
|
|
3154
|
+
var Tile = import_styled_components3.default.button`
|
|
1347
3155
|
display: flex;
|
|
1348
3156
|
flex-direction: column;
|
|
1349
3157
|
gap: 8px;
|
|
1350
3158
|
text-align: left;
|
|
1351
3159
|
width: 100%;
|
|
1352
3160
|
padding: 8px;
|
|
1353
|
-
border: 1px solid ${({ theme }) => theme.colors.neutral200};
|
|
3161
|
+
border: 1px solid ${({ theme, $active }) => $active ? theme.colors.primary600 : theme.colors.neutral200};
|
|
3162
|
+
box-shadow: ${({ theme, $active }) => $active ? `0 0 0 1px ${theme.colors.primary600}` : "none"};
|
|
1354
3163
|
border-radius: 4px;
|
|
1355
3164
|
background: ${({ theme }) => theme.colors.neutral0};
|
|
1356
3165
|
cursor: pointer;
|
|
@@ -1362,13 +3171,13 @@ var Tile = import_styled_components.default.button`
|
|
|
1362
3171
|
outline-offset: 2px;
|
|
1363
3172
|
}
|
|
1364
3173
|
`;
|
|
1365
|
-
var Clamp = (0,
|
|
3174
|
+
var Clamp = (0, import_styled_components3.default)(import_design_system2.Typography)`
|
|
1366
3175
|
display: -webkit-box;
|
|
1367
3176
|
-webkit-line-clamp: 2;
|
|
1368
3177
|
-webkit-box-orient: vertical;
|
|
1369
3178
|
overflow: hidden;
|
|
1370
3179
|
`;
|
|
1371
|
-
var Slider =
|
|
3180
|
+
var Slider = import_styled_components3.default.input`
|
|
1372
3181
|
appearance: none;
|
|
1373
3182
|
-webkit-appearance: none;
|
|
1374
3183
|
width: 8rem;
|
|
@@ -1422,7 +3231,7 @@ var remember = (key, value) => {
|
|
|
1422
3231
|
} catch {
|
|
1423
3232
|
}
|
|
1424
3233
|
};
|
|
1425
|
-
var Frame =
|
|
3234
|
+
var Frame = import_styled_components3.default.div`
|
|
1426
3235
|
width: 100%;
|
|
1427
3236
|
overflow: hidden;
|
|
1428
3237
|
border-radius: 4px;
|
|
@@ -1445,9 +3254,9 @@ function Thumb({
|
|
|
1445
3254
|
blank
|
|
1446
3255
|
}) {
|
|
1447
3256
|
const key = candidates.join("|");
|
|
1448
|
-
const [state, setState] =
|
|
3257
|
+
const [state, setState] = React4.useState({ key, index: 0 });
|
|
1449
3258
|
const index = state.key === key ? state.index : 0;
|
|
1450
|
-
const resolved =
|
|
3259
|
+
const resolved = React4.useRef("");
|
|
1451
3260
|
const report = (value) => {
|
|
1452
3261
|
const tag = `${key}:${value}`;
|
|
1453
3262
|
if (resolved.current !== tag) {
|
|
@@ -1455,11 +3264,11 @@ function Thumb({
|
|
|
1455
3264
|
onResolved?.(value);
|
|
1456
3265
|
}
|
|
1457
3266
|
};
|
|
1458
|
-
|
|
3267
|
+
React4.useEffect(() => {
|
|
1459
3268
|
if (index >= candidates.length) report(-1);
|
|
1460
3269
|
});
|
|
1461
3270
|
if (index >= candidates.length)
|
|
1462
|
-
return blank ? null : /* @__PURE__ */ (0,
|
|
3271
|
+
return blank ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1463
3272
|
Wireframe,
|
|
1464
3273
|
{
|
|
1465
3274
|
template,
|
|
@@ -1467,7 +3276,7 @@ function Thumb({
|
|
|
1467
3276
|
noPreview
|
|
1468
3277
|
}
|
|
1469
3278
|
) });
|
|
1470
|
-
return /* @__PURE__ */ (0,
|
|
3279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1471
3280
|
"img",
|
|
1472
3281
|
{
|
|
1473
3282
|
src: candidates[index],
|
|
@@ -1479,70 +3288,605 @@ function Thumb({
|
|
|
1479
3288
|
candidates[index]
|
|
1480
3289
|
) });
|
|
1481
3290
|
}
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
3291
|
+
var Layout = import_styled_components3.default.div`
|
|
3292
|
+
display: flex;
|
|
3293
|
+
height: min(70vh, 720px);
|
|
3294
|
+
min-height: 320px;
|
|
3295
|
+
`;
|
|
3296
|
+
var Side = import_styled_components3.default.nav`
|
|
3297
|
+
flex: 0 0 ${({ $collapsed }) => $collapsed ? "48px" : "200px"};
|
|
3298
|
+
display: flex;
|
|
3299
|
+
flex-direction: column;
|
|
3300
|
+
gap: 2px;
|
|
3301
|
+
padding-right: 12px;
|
|
3302
|
+
margin-right: 12px;
|
|
3303
|
+
border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
3304
|
+
overflow-y: auto;
|
|
3305
|
+
`;
|
|
3306
|
+
var NavItem = import_styled_components3.default.button`
|
|
3307
|
+
display: flex;
|
|
3308
|
+
align-items: center;
|
|
3309
|
+
justify-content: ${({ $collapsed }) => $collapsed ? "center" : "flex-start"};
|
|
3310
|
+
gap: 8px;
|
|
3311
|
+
width: 100%;
|
|
3312
|
+
padding: 6px 8px;
|
|
3313
|
+
border: 0;
|
|
3314
|
+
border-radius: 4px;
|
|
3315
|
+
cursor: pointer;
|
|
3316
|
+
text-align: left;
|
|
3317
|
+
font-size: 13px;
|
|
3318
|
+
color: ${({ theme, $active }) => $active ? theme.colors.primary600 : theme.colors.neutral700};
|
|
3319
|
+
background: ${({ theme, $active }) => $active ? theme.colors.primary100 : "transparent"};
|
|
3320
|
+
&:hover {
|
|
3321
|
+
background: ${({ theme, $active }) => $active ? theme.colors.primary100 : theme.colors.neutral100};
|
|
3322
|
+
}
|
|
3323
|
+
&:focus-visible {
|
|
3324
|
+
outline: 2px solid ${({ theme }) => theme.colors.primary600};
|
|
3325
|
+
outline-offset: -2px;
|
|
3326
|
+
}
|
|
3327
|
+
.bs-label {
|
|
3328
|
+
flex: 1;
|
|
3329
|
+
overflow: hidden;
|
|
3330
|
+
text-overflow: ellipsis;
|
|
3331
|
+
white-space: nowrap;
|
|
3332
|
+
}
|
|
3333
|
+
.bs-count {
|
|
3334
|
+
color: ${({ theme }) => theme.colors.neutral500};
|
|
3335
|
+
font-size: 12px;
|
|
3336
|
+
}
|
|
3337
|
+
`;
|
|
3338
|
+
var Main = import_styled_components3.default.div`
|
|
3339
|
+
flex: 1;
|
|
3340
|
+
min-width: 0;
|
|
3341
|
+
display: flex;
|
|
3342
|
+
flex-direction: column;
|
|
3343
|
+
gap: 12px;
|
|
3344
|
+
`;
|
|
3345
|
+
var Menu = import_styled_components3.default.div`
|
|
3346
|
+
position: relative;
|
|
3347
|
+
`;
|
|
3348
|
+
var MenuButton = import_styled_components3.default.button`
|
|
3349
|
+
display: inline-flex;
|
|
3350
|
+
align-items: center;
|
|
3351
|
+
gap: 6px;
|
|
3352
|
+
height: 32px;
|
|
3353
|
+
padding: 0 10px;
|
|
3354
|
+
border-radius: 4px;
|
|
3355
|
+
cursor: pointer;
|
|
3356
|
+
font-size: 13px;
|
|
3357
|
+
white-space: nowrap;
|
|
3358
|
+
border: 1px solid ${({ theme, $active }) => $active ? theme.colors.primary600 : theme.colors.neutral200};
|
|
3359
|
+
color: ${({ theme, $active }) => $active ? theme.colors.primary600 : theme.colors.neutral800};
|
|
3360
|
+
background: ${({ theme, $active }) => $active ? theme.colors.primary100 : theme.colors.neutral0};
|
|
3361
|
+
&:focus-visible {
|
|
3362
|
+
outline: 2px solid ${({ theme }) => theme.colors.primary600};
|
|
3363
|
+
outline-offset: 1px;
|
|
3364
|
+
}
|
|
3365
|
+
`;
|
|
3366
|
+
var Popover = import_styled_components3.default.div`
|
|
3367
|
+
position: absolute;
|
|
3368
|
+
top: calc(100% + 4px);
|
|
3369
|
+
left: 0;
|
|
3370
|
+
z-index: 10;
|
|
3371
|
+
min-width: 180px;
|
|
3372
|
+
max-height: 280px;
|
|
3373
|
+
overflow-y: auto;
|
|
3374
|
+
padding: 4px;
|
|
3375
|
+
border: 1px solid ${({ theme }) => theme.colors.neutral200};
|
|
3376
|
+
border-radius: 4px;
|
|
3377
|
+
background: ${({ theme }) => theme.colors.neutral0};
|
|
3378
|
+
box-shadow: 0 2px 12px rgba(33, 33, 52, 0.15);
|
|
3379
|
+
label {
|
|
3380
|
+
display: flex;
|
|
3381
|
+
align-items: center;
|
|
3382
|
+
gap: 8px;
|
|
3383
|
+
padding: 6px 8px;
|
|
3384
|
+
border-radius: 4px;
|
|
3385
|
+
cursor: pointer;
|
|
3386
|
+
font-size: 13px;
|
|
3387
|
+
color: ${({ theme }) => theme.colors.neutral800};
|
|
3388
|
+
}
|
|
3389
|
+
label:hover {
|
|
3390
|
+
background: ${({ theme }) => theme.colors.neutral100};
|
|
3391
|
+
}
|
|
3392
|
+
.bs-count {
|
|
3393
|
+
margin-left: auto;
|
|
3394
|
+
color: ${({ theme }) => theme.colors.neutral500};
|
|
3395
|
+
}
|
|
3396
|
+
`;
|
|
3397
|
+
var Chip = import_styled_components3.default.button`
|
|
3398
|
+
display: inline-flex;
|
|
3399
|
+
align-items: center;
|
|
3400
|
+
gap: 4px;
|
|
3401
|
+
padding: 2px 8px;
|
|
3402
|
+
border-radius: 12px;
|
|
3403
|
+
cursor: pointer;
|
|
3404
|
+
font-size: 12px;
|
|
3405
|
+
border: 1px solid ${({ theme }) => theme.colors.primary200};
|
|
3406
|
+
color: ${({ theme }) => theme.colors.primary700};
|
|
3407
|
+
background: ${({ theme }) => theme.colors.primary100};
|
|
3408
|
+
`;
|
|
3409
|
+
var Badge = import_styled_components3.default.span`
|
|
3410
|
+
padding: 1px 6px;
|
|
3411
|
+
border-radius: 3px;
|
|
3412
|
+
font-size: 10px;
|
|
3413
|
+
font-weight: 600;
|
|
3414
|
+
line-height: 16px;
|
|
3415
|
+
letter-spacing: 0.04em;
|
|
3416
|
+
text-transform: uppercase;
|
|
3417
|
+
color: ${({ theme }) => theme.colors.neutral0};
|
|
3418
|
+
background: ${({ theme }) => theme.colors.neutral800};
|
|
3419
|
+
`;
|
|
3420
|
+
var CardBox = import_styled_components3.default.div`
|
|
3421
|
+
position: relative;
|
|
3422
|
+
&:hover .bs-quick,
|
|
3423
|
+
&:focus-within .bs-quick {
|
|
3424
|
+
opacity: 1;
|
|
3425
|
+
}
|
|
3426
|
+
`;
|
|
3427
|
+
var CardBadges = import_styled_components3.default.div`
|
|
3428
|
+
position: absolute;
|
|
3429
|
+
top: 14px;
|
|
3430
|
+
left: 14px;
|
|
3431
|
+
right: 48px;
|
|
3432
|
+
display: flex;
|
|
3433
|
+
flex-wrap: wrap;
|
|
3434
|
+
gap: 4px;
|
|
3435
|
+
pointer-events: none;
|
|
3436
|
+
`;
|
|
3437
|
+
var Round = import_styled_components3.default.button`
|
|
3438
|
+
position: absolute;
|
|
3439
|
+
right: 14px;
|
|
3440
|
+
display: inline-flex;
|
|
3441
|
+
align-items: center;
|
|
3442
|
+
justify-content: center;
|
|
3443
|
+
width: 28px;
|
|
3444
|
+
height: 28px;
|
|
3445
|
+
padding: 0;
|
|
3446
|
+
border-radius: 50%;
|
|
3447
|
+
cursor: pointer;
|
|
3448
|
+
border: 1px solid ${({ theme, $primary }) => $primary ? theme.colors.primary600 : theme.colors.neutral200};
|
|
3449
|
+
color: ${({ theme, $on, $primary }) => $primary ? theme.colors.neutral0 : $on ? theme.colors.warning500 : theme.colors.neutral600};
|
|
3450
|
+
background: ${({ theme, $primary }) => $primary ? theme.colors.primary600 : theme.colors.neutral0};
|
|
3451
|
+
&:focus-visible {
|
|
3452
|
+
outline: 2px solid ${({ theme }) => theme.colors.primary600};
|
|
3453
|
+
outline-offset: 1px;
|
|
3454
|
+
}
|
|
3455
|
+
&.bs-quick {
|
|
3456
|
+
opacity: 0;
|
|
3457
|
+
transition: opacity 120ms;
|
|
3458
|
+
}
|
|
3459
|
+
`;
|
|
3460
|
+
var Mono = import_styled_components3.default.code`
|
|
3461
|
+
font-size: 12px;
|
|
3462
|
+
color: ${({ theme }) => theme.colors.neutral600};
|
|
3463
|
+
`;
|
|
3464
|
+
var SIDEBAR_KEY = "blockscene:gallery-sidebar";
|
|
3465
|
+
var readCollapsed = () => {
|
|
3466
|
+
try {
|
|
3467
|
+
return window.localStorage.getItem(SIDEBAR_KEY) === "collapsed";
|
|
3468
|
+
} catch {
|
|
3469
|
+
return false;
|
|
3470
|
+
}
|
|
3471
|
+
};
|
|
3472
|
+
var TYPE_ICONS = { hero: "hero", text: "text", media: "image", listing: "list", cards: "cards", cta: "link", form: "form", layout: "layout" };
|
|
3473
|
+
var FILTER_MENUS = ["tags", "media", "content"];
|
|
3474
|
+
var toggled = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];
|
|
3475
|
+
function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
|
|
3476
|
+
const [open, setOpen] = React4.useState(false);
|
|
3477
|
+
const ref = React4.useRef(null);
|
|
3478
|
+
React4.useEffect(() => {
|
|
3479
|
+
if (!open) return;
|
|
3480
|
+
const down = (event) => {
|
|
3481
|
+
if (!ref.current?.contains(event.target)) setOpen(false);
|
|
3482
|
+
};
|
|
3483
|
+
const key = (event) => {
|
|
3484
|
+
if (event.key !== "Escape") return;
|
|
3485
|
+
event.stopPropagation();
|
|
3486
|
+
event.preventDefault();
|
|
3487
|
+
setOpen(false);
|
|
3488
|
+
};
|
|
3489
|
+
document.addEventListener("mousedown", down, true);
|
|
3490
|
+
window.addEventListener("keydown", key, true);
|
|
3491
|
+
return () => {
|
|
3492
|
+
document.removeEventListener("mousedown", down, true);
|
|
3493
|
+
window.removeEventListener("keydown", key, true);
|
|
3494
|
+
};
|
|
3495
|
+
}, [open]);
|
|
3496
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Menu, { ref, "data-testid": `gallery-filter-${name}`, children: [
|
|
3497
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3498
|
+
MenuButton,
|
|
3499
|
+
{
|
|
3500
|
+
type: "button",
|
|
3501
|
+
"aria-expanded": open,
|
|
3502
|
+
$active: picked.length > 0,
|
|
3503
|
+
onClick: () => setOpen(!open),
|
|
3504
|
+
children: [
|
|
3505
|
+
picked.length ? `${label} (${picked.length})` : label,
|
|
3506
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "chevron", size: 14 })
|
|
3507
|
+
]
|
|
3508
|
+
}
|
|
3509
|
+
),
|
|
3510
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Popover, { role: "group", "aria-label": label, children: options.map(([value, count]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
|
|
3511
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3512
|
+
"input",
|
|
3513
|
+
{
|
|
3514
|
+
type: "checkbox",
|
|
3515
|
+
checked: picked.includes(value),
|
|
3516
|
+
onChange: () => onChange(toggled(picked, value)),
|
|
3517
|
+
"data-testid": `gallery-option-${name}-${value}`
|
|
3518
|
+
}
|
|
3519
|
+
),
|
|
3520
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: labelOf(value) }),
|
|
3521
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-count", children: count })
|
|
3522
|
+
] }, value)) })
|
|
3523
|
+
] });
|
|
3524
|
+
}
|
|
3525
|
+
function Badges({ entry, t, tags }) {
|
|
3526
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3527
|
+
entry.facets.map((facet) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: t.facets[facet] || facet }, facet)),
|
|
3528
|
+
tags && entry.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: tag }, `tag:${tag}`))
|
|
3529
|
+
] });
|
|
3530
|
+
}
|
|
3531
|
+
function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, onStar }) {
|
|
3532
|
+
const t = useMessages();
|
|
3533
|
+
const timer = React4.useRef(null);
|
|
3534
|
+
React4.useEffect(() => () => clearTimeout(timer.current), []);
|
|
3535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(CardBox, { title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
|
|
3536
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3537
|
+
Tile,
|
|
3538
|
+
{
|
|
3539
|
+
type: "button",
|
|
3540
|
+
$active: active,
|
|
3541
|
+
onClick: (event) => {
|
|
3542
|
+
clearTimeout(timer.current);
|
|
3543
|
+
if (event.detail === 2) onInsert();
|
|
3544
|
+
else if (event.detail === 1) timer.current = setTimeout(onOpen, 220);
|
|
3545
|
+
else onOpen();
|
|
3546
|
+
},
|
|
3547
|
+
onKeyDown: (event) => {
|
|
3548
|
+
if (event.key !== "Enter") return;
|
|
3549
|
+
event.preventDefault();
|
|
3550
|
+
onInsert();
|
|
3551
|
+
},
|
|
3552
|
+
children: [
|
|
3553
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3554
|
+
Thumb,
|
|
3555
|
+
{
|
|
3556
|
+
candidates: entry.candidates,
|
|
3557
|
+
template: entry.template,
|
|
3558
|
+
palette,
|
|
3559
|
+
noPreview: t.noPreview
|
|
3560
|
+
}
|
|
3561
|
+
),
|
|
3562
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
|
|
3563
|
+
entry.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
|
|
3564
|
+
showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3565
|
+
import_design_system2.Typography,
|
|
3566
|
+
{
|
|
3567
|
+
variant: "pi",
|
|
3568
|
+
textColor: "neutral500",
|
|
3569
|
+
style: { fontStyle: "italic" },
|
|
3570
|
+
"data-testid": "block-fields",
|
|
3571
|
+
children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ")
|
|
3572
|
+
}
|
|
3573
|
+
)
|
|
3574
|
+
]
|
|
3575
|
+
}
|
|
3576
|
+
),
|
|
3577
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardBadges, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badges, { entry, t }) }),
|
|
3578
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3579
|
+
Round,
|
|
3580
|
+
{
|
|
3581
|
+
type: "button",
|
|
3582
|
+
style: { top: 12 },
|
|
3583
|
+
$on: starred,
|
|
3584
|
+
"aria-pressed": starred,
|
|
3585
|
+
"aria-label": starred ? t.unstar : t.star,
|
|
3586
|
+
title: starred ? t.unstar : t.star,
|
|
3587
|
+
onClick: onStar,
|
|
3588
|
+
"data-testid": `gallery-star-${entry.uid}`,
|
|
3589
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "star", size: 16, filled: starred })
|
|
3590
|
+
}
|
|
3591
|
+
),
|
|
3592
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3593
|
+
Round,
|
|
3594
|
+
{
|
|
3595
|
+
type: "button",
|
|
3596
|
+
className: "bs-quick",
|
|
3597
|
+
style: { top: 46 },
|
|
3598
|
+
$primary: true,
|
|
3599
|
+
"aria-label": t.f("quickInsert", { label: entry.label }),
|
|
3600
|
+
title: t.f("quickInsert", { label: entry.label }),
|
|
3601
|
+
onClick: onInsert,
|
|
3602
|
+
"data-testid": `gallery-quick-${entry.uid}`,
|
|
3603
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "plus", size: 16 })
|
|
3604
|
+
}
|
|
3605
|
+
)
|
|
3606
|
+
] });
|
|
3607
|
+
}
|
|
3608
|
+
var Scrim = import_styled_components3.default.div`
|
|
3609
|
+
position: absolute;
|
|
3610
|
+
inset: 0;
|
|
3611
|
+
z-index: 4;
|
|
3612
|
+
opacity: 0.35;
|
|
3613
|
+
background: ${({ theme }) => theme.colors.neutral800};
|
|
3614
|
+
`;
|
|
3615
|
+
var Panel = import_styled_components3.default.section`
|
|
3616
|
+
position: absolute;
|
|
3617
|
+
inset: 16px;
|
|
3618
|
+
z-index: 5;
|
|
3619
|
+
display: flex;
|
|
3620
|
+
flex-direction: column;
|
|
3621
|
+
overflow: hidden;
|
|
3622
|
+
border: 1px solid ${({ theme }) => theme.colors.neutral200};
|
|
3623
|
+
border-radius: 4px;
|
|
3624
|
+
background: ${({ theme }) => theme.colors.neutral0};
|
|
3625
|
+
box-shadow: ${({ theme }) => theme.shadows?.popupShadow || "0 8px 32px rgba(33, 33, 52, 0.3)"};
|
|
3626
|
+
transform-origin: top left;
|
|
3627
|
+
`;
|
|
3628
|
+
var Stage = import_styled_components3.default.div`
|
|
3629
|
+
position: relative;
|
|
3630
|
+
flex: 1;
|
|
3631
|
+
min-height: 0;
|
|
3632
|
+
overflow: hidden;
|
|
3633
|
+
background-color: ${({ theme }) => stageBackground(theme).backgroundColor};
|
|
3634
|
+
background-image: ${({ theme }) => stageBackground(theme).backgroundImage};
|
|
3635
|
+
background-size: 24px 24px;
|
|
3636
|
+
`;
|
|
3637
|
+
var Still = import_styled_components3.default.div`
|
|
3638
|
+
position: absolute;
|
|
3639
|
+
inset: 0;
|
|
3640
|
+
/* Hidden once the live page has faded in over it (device widths would show it in the gutters). */
|
|
3641
|
+
visibility: ${({ $covered }) => $covered ? "hidden" : "visible"};
|
|
3642
|
+
transition: visibility 0s linear ${({ $covered }) => $covered ? "200ms" : "0s"};
|
|
3643
|
+
> [data-thumb] {
|
|
3644
|
+
width: 100%;
|
|
3645
|
+
height: 100%;
|
|
3646
|
+
aspect-ratio: auto;
|
|
3647
|
+
background: transparent;
|
|
3648
|
+
}
|
|
3649
|
+
img,
|
|
3650
|
+
svg {
|
|
3651
|
+
width: 100%;
|
|
3652
|
+
height: 100%;
|
|
3653
|
+
object-fit: contain;
|
|
3654
|
+
}
|
|
3655
|
+
`;
|
|
3656
|
+
var Live = import_styled_components3.default.iframe`
|
|
3657
|
+
position: absolute;
|
|
3658
|
+
top: 0;
|
|
3659
|
+
border: 0;
|
|
3660
|
+
background: white;
|
|
3661
|
+
transform-origin: top left;
|
|
3662
|
+
opacity: ${({ $shown }) => $shown ? 1 : 0};
|
|
3663
|
+
transition: opacity 200ms ease-out;
|
|
3664
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3665
|
+
transition: none;
|
|
3666
|
+
}
|
|
3667
|
+
`;
|
|
3668
|
+
var Strip = import_styled_components3.default.div`
|
|
3669
|
+
display: flex;
|
|
3670
|
+
flex-direction: column;
|
|
3671
|
+
gap: 6px;
|
|
3672
|
+
padding: 10px 12px;
|
|
3673
|
+
border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
3674
|
+
`;
|
|
3675
|
+
var FieldsButton = import_styled_components3.default.button`
|
|
3676
|
+
border: 0;
|
|
3677
|
+
padding: 0;
|
|
3678
|
+
cursor: pointer;
|
|
3679
|
+
background: none;
|
|
3680
|
+
font-size: 12px;
|
|
3681
|
+
color: ${({ theme }) => theme.colors.primary600};
|
|
3682
|
+
`;
|
|
3683
|
+
var reducedMotion = () => {
|
|
3684
|
+
try {
|
|
3685
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
3686
|
+
} catch {
|
|
3687
|
+
return false;
|
|
3688
|
+
}
|
|
3689
|
+
};
|
|
3690
|
+
var flip = (panel, scrim, card, back) => {
|
|
3691
|
+
if (!panel?.animate || reducedMotion()) return null;
|
|
3692
|
+
const to = panel.getBoundingClientRect();
|
|
3693
|
+
const from = card?.getBoundingClientRect();
|
|
3694
|
+
const timing = { duration: 250, easing: "cubic-bezier(0.2, 0, 0, 1)", fill: back ? "forwards" : "none" };
|
|
3695
|
+
const frames = [
|
|
3696
|
+
from?.width && to.width ? { transform: `translate(${from.left - to.left}px, ${from.top - to.top}px) scale(${from.width / to.width}, ${from.height / to.height})`, opacity: 0.6 } : { transform: "scale(0.96)", opacity: 0 },
|
|
3697
|
+
{ transform: "none", opacity: 1 }
|
|
3698
|
+
];
|
|
3699
|
+
const dim = [{ opacity: 0 }, { opacity: 0.35 }];
|
|
3700
|
+
scrim?.animate(back ? dim.reverse() : dim, timing);
|
|
3701
|
+
return panel.animate(back ? frames.reverse() : frames, timing);
|
|
3702
|
+
};
|
|
3703
|
+
var newChannel = () => crypto.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
3704
|
+
function useLiveSource(entry, config, components, get, contentType, locale) {
|
|
3705
|
+
const editor = config?.editor || {};
|
|
3706
|
+
const [native, setNative] = React4.useState(null);
|
|
3707
|
+
const plain = editor.blockPreviewUrl ? blockPreviewSrc(editor.blockPreviewUrl, entry.uid, { locale: locale || "" }) : null;
|
|
3708
|
+
React4.useEffect(() => {
|
|
3709
|
+
if (editor.blockPreviewUrl || editor.previewUrl || !contentType || !get) return;
|
|
3710
|
+
let active = true;
|
|
3711
|
+
get(`/content-manager/preview/url/${contentType}?${new URLSearchParams({ status: "draft", ...locale ? { locale } : {} })}`).then(({ data }) => {
|
|
3712
|
+
if (active && typeof data?.data?.url === "string") setNative(`${new URL(data.data.url).origin}/block-preview/page`);
|
|
3713
|
+
}).catch(() => {
|
|
3714
|
+
});
|
|
3715
|
+
return () => {
|
|
3716
|
+
active = false;
|
|
3717
|
+
};
|
|
3718
|
+
}, [editor.blockPreviewUrl, editor.previewUrl, contentType, locale, get]);
|
|
3719
|
+
const channel = React4.useMemo(newChannel, []);
|
|
3720
|
+
if (editor.blockPreviewUrl) return plain ? { kind: "plain", src: plain, origin: "", channel } : null;
|
|
3721
|
+
const base = editor.previewUrl || native;
|
|
3722
|
+
if (!base) return null;
|
|
3723
|
+
try {
|
|
3724
|
+
const url = new URL(base);
|
|
3725
|
+
url.searchParams.set("channel", channel);
|
|
3726
|
+
return { kind: "bridge", src: url.href, origin: url.origin, channel };
|
|
3727
|
+
} catch {
|
|
3728
|
+
return null;
|
|
3729
|
+
}
|
|
3730
|
+
}
|
|
3731
|
+
var LIVE_TIMEOUT = 8e3;
|
|
3732
|
+
function Magnify({ entry, palette, config, components, get, contentType, locale, starred, onStar, onInsert, onClose, cardOf }) {
|
|
3733
|
+
const t = useMessages();
|
|
3734
|
+
const panel = React4.useRef(null);
|
|
3735
|
+
const scrim = React4.useRef(null);
|
|
3736
|
+
const closeButton = React4.useRef(null);
|
|
3737
|
+
const frame2 = React4.useRef(null);
|
|
3738
|
+
const closing = React4.useRef(false);
|
|
3739
|
+
const [stageEl, setStageEl] = React4.useState(null);
|
|
3740
|
+
const stage = useStageSize(stageEl);
|
|
3741
|
+
const [device, setDevice] = React4.useState("fit");
|
|
3742
|
+
const [fields, setFields] = React4.useState(false);
|
|
3743
|
+
const [state, setState] = React4.useState("loading");
|
|
3744
|
+
const live = useLiveSource(entry, config, components, get, contentType, locale);
|
|
3745
|
+
React4.useLayoutEffect(() => {
|
|
3746
|
+
flip(panel.current, scrim.current, cardOf(entry.uid), false);
|
|
3747
|
+
closeButton.current?.querySelector("button")?.focus({ preventScroll: true });
|
|
3748
|
+
}, []);
|
|
3749
|
+
const close = () => {
|
|
3750
|
+
if (closing.current) return;
|
|
3751
|
+
closing.current = true;
|
|
3752
|
+
const card = cardOf(entry.uid);
|
|
3753
|
+
const done = () => {
|
|
3754
|
+
onClose();
|
|
3755
|
+
card?.querySelector("button")?.focus({ preventScroll: true });
|
|
3756
|
+
};
|
|
3757
|
+
const animation = flip(panel.current, scrim.current, card, true);
|
|
3758
|
+
if (animation) animation.onfinish = done;
|
|
3759
|
+
else done();
|
|
3760
|
+
};
|
|
3761
|
+
const closeRef = React4.useRef(close);
|
|
3762
|
+
closeRef.current = close;
|
|
3763
|
+
React4.useEffect(() => {
|
|
3764
|
+
const key = (event) => {
|
|
3765
|
+
if (event.key !== "Escape") return;
|
|
3766
|
+
event.stopPropagation();
|
|
3767
|
+
event.preventDefault();
|
|
3768
|
+
closeRef.current();
|
|
3769
|
+
};
|
|
3770
|
+
window.addEventListener("keydown", key, true);
|
|
3771
|
+
return () => window.removeEventListener("keydown", key, true);
|
|
3772
|
+
}, []);
|
|
3773
|
+
const src = live?.src;
|
|
3774
|
+
React4.useEffect(() => {
|
|
3775
|
+
if (!live) return;
|
|
3776
|
+
setState("loading");
|
|
3777
|
+
const timer = setTimeout(() => setState((s) => s === "ready" ? s : "failed"), LIVE_TIMEOUT);
|
|
3778
|
+
const receive = (event) => {
|
|
3779
|
+
if (live.kind !== "bridge" || !isPreviewMessage(event, live.origin, frame2.current?.contentWindow, live.channel, "ready")) return;
|
|
3780
|
+
clearTimeout(timer);
|
|
3781
|
+
setState("ready");
|
|
3782
|
+
let blocks = [];
|
|
3783
|
+
try {
|
|
3784
|
+
const row = { ...componentDefaults(components[entry.uid], components), __component: entry.uid, __temp_key__: "blockscene-magnify" };
|
|
3785
|
+
blocks = projectPage([row], components, window.location.origin);
|
|
3786
|
+
} catch {
|
|
3787
|
+
}
|
|
3788
|
+
frame2.current?.contentWindow?.postMessage(
|
|
3789
|
+
{ protocol: PROTOCOL, channel: live.channel, type: "update-page", blocks, groups: null, locale: t.locale, mode: "preview" },
|
|
3790
|
+
live.origin
|
|
3791
|
+
);
|
|
3792
|
+
};
|
|
3793
|
+
window.addEventListener("message", receive);
|
|
3794
|
+
return () => {
|
|
3795
|
+
clearTimeout(timer);
|
|
3796
|
+
window.removeEventListener("message", receive);
|
|
3797
|
+
};
|
|
3798
|
+
}, [src]);
|
|
3799
|
+
const onLoad = () => {
|
|
3800
|
+
if (live?.kind === "plain") setState("ready");
|
|
3801
|
+
else frame2.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel: live.channel, type: "ping" }, live.origin);
|
|
3802
|
+
};
|
|
3803
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3804
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Scrim, { ref: scrim, onClick: close, "data-testid": "gallery-magnify-scrim" }),
|
|
3805
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Panel, { ref: panel, "aria-label": entry.label, "data-testid": "gallery-detail", "data-live": live ? state : "none", children: [
|
|
3806
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, padding: 2, alignItems: "center", justifyContent: "space-between", children: [
|
|
3807
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { gap: 1, role: "group", "aria-label": t.deviceGroup, "data-testid": "gallery-magnify-devices", children: Object.keys(DEVICES).map((value) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3808
|
+
Tool,
|
|
3809
|
+
{
|
|
3810
|
+
icon: value,
|
|
3811
|
+
label: DEVICES[value] ? `${t.device[value]} \xB7 ${DEVICES[value]} px` : t.device[value],
|
|
3812
|
+
active: device === value,
|
|
3813
|
+
onClick: () => setDevice(value)
|
|
3814
|
+
},
|
|
3815
|
+
value
|
|
3816
|
+
)) }),
|
|
3817
|
+
live && state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "gallery-magnify-note", children: t.livePreviewFailed }),
|
|
3818
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: closeButton, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "close", label: t.closeDetail, onClick: close }) })
|
|
3819
|
+
] }),
|
|
3820
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Stage, { ref: setStageEl, $device: device !== "fit", "data-device": device, children: [
|
|
3821
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Still, { $covered: Boolean(live) && state === "ready", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview, eager: true }) }),
|
|
3822
|
+
live && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3823
|
+
Live,
|
|
3824
|
+
{
|
|
3825
|
+
ref: frame2,
|
|
3826
|
+
title: t.blockPreview,
|
|
3827
|
+
src: live.src,
|
|
3828
|
+
sandbox: "allow-scripts allow-same-origin",
|
|
3829
|
+
referrerPolicy: "no-referrer",
|
|
3830
|
+
onLoad,
|
|
3831
|
+
$shown: state === "ready",
|
|
3832
|
+
style: frameStyle(device, stage),
|
|
3833
|
+
"data-testid": "gallery-magnify-frame"
|
|
3834
|
+
},
|
|
3835
|
+
live.src
|
|
3836
|
+
)
|
|
3837
|
+
] }),
|
|
3838
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Strip, { children: [
|
|
3839
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
|
|
3840
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "omega", fontWeight: "bold", tag: "h3", ellipsis: true, children: entry.label }),
|
|
3841
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Mono, { children: entry.uid }),
|
|
3842
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: t.typologies[entry.typology] || entry.typology }),
|
|
3843
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badges, { entry, t, tags: true }),
|
|
3844
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
|
|
3845
|
+
entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FieldsButton, { type: "button", "aria-expanded": fields, onClick: () => setFields(!fields), "data-testid": "gallery-detail-fields-toggle", children: `${t.showFields} (${entry.fields.length})` }),
|
|
3846
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "star", label: starred ? t.unstar : t.star, active: starred, onClick: onStar, "data-testid": "gallery-detail-star" }),
|
|
3847
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { onClick: onInsert, "data-testid": "gallery-insert", children: t.insert })
|
|
3848
|
+
] })
|
|
3849
|
+
] }),
|
|
3850
|
+
entry.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Clamp, { variant: "pi", textColor: "neutral700", children: entry.description }),
|
|
3851
|
+
fields && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { gap: 3, wrap: "wrap", "data-testid": "gallery-detail-fields", children: entry.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral800", children: [
|
|
3852
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: field.name }),
|
|
3853
|
+
" ",
|
|
3854
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Mono, { children: field.type })
|
|
3855
|
+
] }, field.name)) })
|
|
3856
|
+
] })
|
|
3857
|
+
] })
|
|
3858
|
+
] });
|
|
3859
|
+
}
|
|
3860
|
+
var NO_FILTERS = { tags: [], media: [], content: [] };
|
|
3861
|
+
function ZoneGallery({
|
|
3862
|
+
zone,
|
|
3863
|
+
components,
|
|
3864
|
+
add,
|
|
3865
|
+
Modal: Modal2,
|
|
3866
|
+
Toggle,
|
|
3867
|
+
get,
|
|
3868
|
+
put,
|
|
3869
|
+
controlled,
|
|
3870
|
+
contentType,
|
|
3871
|
+
locale
|
|
3872
|
+
}) {
|
|
3873
|
+
const t = useMessages();
|
|
3874
|
+
const grid = React4.useRef(null);
|
|
3875
|
+
const cardOf = (uid) => grid.current?.querySelector(`[data-testid="blockscene-${CSS.escape(uid)}"]`) || null;
|
|
3876
|
+
const [ownOpen, setOwnOpen] = React4.useState(false);
|
|
3877
|
+
const open = controlled ? controlled.open : ownOpen;
|
|
3878
|
+
const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
|
|
3879
|
+
const [query, setQuery] = React4.useState("");
|
|
3880
|
+
const [view, setView] = React4.useState("all");
|
|
3881
|
+
const [picked, setPicked] = React4.useState(NO_FILTERS);
|
|
3882
|
+
const [detail, setDetail] = React4.useState(null);
|
|
3883
|
+
const [collapsed, setCollapsed] = React4.useState(readCollapsed);
|
|
3884
|
+
const [prefs, setPrefs] = React4.useState({ starred: [], recent: [] });
|
|
3885
|
+
const [showFields, setShowFields] = React4.useState(readShowFields);
|
|
3886
|
+
const [columns, setColumns] = React4.useState(readColumns);
|
|
3887
|
+
const [config, setConfig] = React4.useState(null);
|
|
3888
|
+
const [error, setError] = React4.useState("");
|
|
3889
|
+
React4.useEffect(() => {
|
|
1546
3890
|
if (controlled) return;
|
|
1547
3891
|
const onClick = (event) => {
|
|
1548
3892
|
const button = event.target?.closest?.("button");
|
|
@@ -1554,36 +3898,56 @@ function ZoneGallery({
|
|
|
1554
3898
|
document.addEventListener("click", onClick, true);
|
|
1555
3899
|
return () => document.removeEventListener("click", onClick, true);
|
|
1556
3900
|
}, [controlled, zone.name, zone.label]);
|
|
1557
|
-
|
|
3901
|
+
React4.useEffect(() => {
|
|
1558
3902
|
if (!open) return;
|
|
1559
3903
|
let active = true;
|
|
1560
3904
|
setError("");
|
|
1561
3905
|
setConfig(null);
|
|
3906
|
+
setDetail(null);
|
|
1562
3907
|
get("/blockscene/catalog").then(({ data }) => {
|
|
1563
3908
|
if (active) setConfig(data);
|
|
1564
3909
|
}).catch(() => {
|
|
1565
3910
|
if (active) setError(t.failed);
|
|
1566
3911
|
});
|
|
3912
|
+
get("/blockscene/me/prefs").then(({ data }) => {
|
|
3913
|
+
if (active && data) setPrefs({ starred: data.starred || [], recent: data.recent || [] });
|
|
3914
|
+
}).catch(() => {
|
|
3915
|
+
});
|
|
1567
3916
|
return () => {
|
|
1568
3917
|
active = false;
|
|
1569
3918
|
};
|
|
1570
3919
|
}, [open, get, t.failed]);
|
|
1571
|
-
const
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
);
|
|
1577
|
-
const
|
|
3920
|
+
const savePrefs = (next) => {
|
|
3921
|
+
setPrefs(next);
|
|
3922
|
+
put?.("/blockscene/me/prefs", next).catch(() => {
|
|
3923
|
+
});
|
|
3924
|
+
};
|
|
3925
|
+
const star = (uid) => savePrefs({ ...prefs, starred: toggled(prefs.starred, uid) });
|
|
3926
|
+
const options = config ? optionsFor(zone, components, config) : null;
|
|
3927
|
+
const inZone = (list) => options ? list.filter((uid) => options.uids.includes(uid)) : [];
|
|
3928
|
+
const filter = {
|
|
3929
|
+
...picked,
|
|
3930
|
+
typology: TYPOLOGIES.includes(view) ? view : void 0,
|
|
3931
|
+
uids: view === "recent" ? prefs.recent : view === "starred" ? prefs.starred : void 0
|
|
3932
|
+
};
|
|
3933
|
+
let entries = config ? entriesFor(zone, components, config, query, filter) : [];
|
|
3934
|
+
if (view === "recent") entries = [...entries].sort((a, b) => prefs.recent.indexOf(a.uid) - prefs.recent.indexOf(b.uid));
|
|
3935
|
+
const chosen = entries.find((entry) => entry.uid === detail);
|
|
3936
|
+
const chips = FILTER_MENUS.flatMap((menu) => picked[menu].map((value) => ({ menu, value })));
|
|
3937
|
+
const filtering = query.trim() !== "" || view !== "all" || chips.length > 0;
|
|
1578
3938
|
const reset = () => {
|
|
1579
3939
|
setQuery("");
|
|
1580
|
-
|
|
3940
|
+
setView("all");
|
|
3941
|
+
setPicked(NO_FILTERS);
|
|
1581
3942
|
};
|
|
3943
|
+
const labelOf = (menu, value) => menu === "tags" ? value : t.facets[value] || value;
|
|
1582
3944
|
const select = (uid) => {
|
|
1583
3945
|
try {
|
|
1584
3946
|
if (controlled ? (controlled.onSelect(uid), true) : add(zone, uid)) {
|
|
3947
|
+
savePrefs({ ...prefs, recent: [uid, ...prefs.recent.filter((item) => item !== uid)].slice(0, 20) });
|
|
1585
3948
|
setOpen(false);
|
|
1586
3949
|
setQuery("");
|
|
3950
|
+
setDetail(null);
|
|
1587
3951
|
}
|
|
1588
3952
|
} catch {
|
|
1589
3953
|
setError(t.insertFailed);
|
|
@@ -1597,164 +3961,207 @@ function ZoneGallery({
|
|
|
1597
3961
|
setShowFields(value);
|
|
1598
3962
|
remember(SHOW_FIELDS_KEY, String(value));
|
|
1599
3963
|
};
|
|
1600
|
-
|
|
3964
|
+
const toggleSidebar = () => {
|
|
3965
|
+
setCollapsed(!collapsed);
|
|
3966
|
+
remember(SIDEBAR_KEY, collapsed ? "expanded" : "collapsed");
|
|
3967
|
+
};
|
|
3968
|
+
const nav = (key, icon, label, count) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
3969
|
+
NavItem,
|
|
3970
|
+
{
|
|
3971
|
+
type: "button",
|
|
3972
|
+
$active: view === key,
|
|
3973
|
+
$collapsed: collapsed,
|
|
3974
|
+
"aria-current": view === key ? "true" : void 0,
|
|
3975
|
+
"aria-label": collapsed ? `${label} (${count})` : void 0,
|
|
3976
|
+
title: collapsed ? `${label} (${count})` : void 0,
|
|
3977
|
+
onClick: () => setView(key),
|
|
3978
|
+
"data-testid": `gallery-nav-${key}`,
|
|
3979
|
+
children: [
|
|
3980
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: icon }),
|
|
3981
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
3982
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-label", children: label }),
|
|
3983
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-count", children: count })
|
|
3984
|
+
] })
|
|
3985
|
+
]
|
|
3986
|
+
},
|
|
3987
|
+
key
|
|
3988
|
+
);
|
|
3989
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1601
3990
|
Modal2,
|
|
1602
3991
|
{
|
|
1603
3992
|
open,
|
|
1604
3993
|
onOpenChange: setOpen,
|
|
1605
3994
|
title: t.gallery,
|
|
1606
|
-
trigger: controlled ? null : /* @__PURE__ */ (0,
|
|
1607
|
-
|
|
3995
|
+
trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3996
|
+
import_design_system2.Button,
|
|
1608
3997
|
{
|
|
1609
3998
|
variant: "secondary",
|
|
1610
3999
|
fullWidth: true,
|
|
1611
4000
|
onClick: () => setOpen(true),
|
|
1612
4001
|
"data-testid": `open-gallery-${zone.name}`,
|
|
1613
|
-
children:
|
|
1614
|
-
t.add,
|
|
1615
|
-
": ",
|
|
1616
|
-
zone.name
|
|
1617
|
-
]
|
|
4002
|
+
children: t.add
|
|
1618
4003
|
}
|
|
1619
4004
|
),
|
|
1620
|
-
children: /* @__PURE__ */ (0,
|
|
1621
|
-
/* @__PURE__ */ (0,
|
|
1622
|
-
/* @__PURE__ */ (0,
|
|
1623
|
-
|
|
4005
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Layout, { children: [
|
|
4006
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Side, { $collapsed: collapsed, "aria-label": t.gallery, "data-testid": `gallery-sidebar-${zone.name}`, "data-collapsed": collapsed, children: [
|
|
4007
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { justifyContent: collapsed ? "center" : "flex-end", paddingBottom: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4008
|
+
Tool,
|
|
1624
4009
|
{
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
"data-testid": `block-count-${zone.name}`,
|
|
1630
|
-
"aria-live": "polite",
|
|
1631
|
-
children: filtering ? t.f("countFiltered", { shown: entries.length, total }) : t.f("countAll", { count: total })
|
|
1632
|
-
}
|
|
1633
|
-
),
|
|
1634
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1635
|
-
import_design_system.Searchbar,
|
|
1636
|
-
{
|
|
1637
|
-
name: `block-search-${zone.name}`,
|
|
1638
|
-
value: query,
|
|
1639
|
-
placeholder: t.search,
|
|
1640
|
-
clearLabel: t.clear,
|
|
1641
|
-
onClear: () => setQuery(""),
|
|
1642
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1643
|
-
children: t.search
|
|
4010
|
+
icon: "sidebar",
|
|
4011
|
+
label: collapsed ? t.expandSidebar : t.collapseSidebar,
|
|
4012
|
+
onClick: toggleSidebar,
|
|
4013
|
+
"data-testid": "gallery-sidebar-toggle"
|
|
1644
4014
|
}
|
|
1645
4015
|
) }),
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1661
|
-
import_design_system.SingleSelectOption,
|
|
1662
|
-
{
|
|
1663
|
-
value: name,
|
|
1664
|
-
children: `${name} (${count})`
|
|
1665
|
-
},
|
|
1666
|
-
name
|
|
1667
|
-
))
|
|
1668
|
-
]
|
|
1669
|
-
}
|
|
1670
|
-
)
|
|
1671
|
-
}
|
|
1672
|
-
),
|
|
1673
|
-
Toggle && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1674
|
-
Toggle,
|
|
1675
|
-
{
|
|
1676
|
-
name: `block-fields-${zone.name}`,
|
|
1677
|
-
label: t.showFields,
|
|
1678
|
-
hint: t.showFieldsHint,
|
|
1679
|
-
value: showFields,
|
|
1680
|
-
onChange: changeShowFields
|
|
1681
|
-
}
|
|
1682
|
-
),
|
|
1683
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
|
|
1684
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1685
|
-
import_design_system.Typography,
|
|
4016
|
+
options && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
4017
|
+
nav("all", "grid", t.nav.all, options.total),
|
|
4018
|
+
nav("recent", "clock", t.nav.recent, inZone(prefs.recent).length),
|
|
4019
|
+
nav("starred", "star", t.nav.starred, inZone(prefs.starred).length),
|
|
4020
|
+
!collapsed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Box, { paddingTop: 4, paddingBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", children: t.typologiesTitle }) }),
|
|
4021
|
+
options.typologies.map(
|
|
4022
|
+
([name, count]) => nav(name, TYPE_ICONS[name] || "text", t.typologies[name] || name, count)
|
|
4023
|
+
)
|
|
4024
|
+
] })
|
|
4025
|
+
] }),
|
|
4026
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Main, { children: [
|
|
4027
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
|
|
4028
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4029
|
+
import_design_system2.Typography,
|
|
1686
4030
|
{
|
|
1687
|
-
variant: "
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
4031
|
+
variant: "omega",
|
|
4032
|
+
fontWeight: "bold",
|
|
4033
|
+
textColor: "neutral800",
|
|
4034
|
+
style: { whiteSpace: "nowrap" },
|
|
4035
|
+
"data-testid": `block-count-${zone.name}`,
|
|
4036
|
+
"aria-live": "polite",
|
|
4037
|
+
children: filtering ? t.f("countFiltered", { shown: entries.length, total: options?.total || 0 }) : t.f("countAll", { count: options?.total || 0 })
|
|
1691
4038
|
}
|
|
1692
4039
|
),
|
|
1693
|
-
/* @__PURE__ */ (0,
|
|
1694
|
-
|
|
4040
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4041
|
+
import_design_system2.Searchbar,
|
|
4042
|
+
{
|
|
4043
|
+
name: `block-search-${zone.name}`,
|
|
4044
|
+
value: query,
|
|
4045
|
+
placeholder: t.search,
|
|
4046
|
+
clearLabel: t.clear,
|
|
4047
|
+
onClear: () => setQuery(""),
|
|
4048
|
+
onChange: (e) => setQuery(e.target.value),
|
|
4049
|
+
children: t.search
|
|
4050
|
+
}
|
|
4051
|
+
) }),
|
|
4052
|
+
options && FILTER_MENUS.filter((menu) => options[menu].length > 0).map((menu) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4053
|
+
FilterMenu,
|
|
4054
|
+
{
|
|
4055
|
+
name: menu,
|
|
4056
|
+
label: t.filters[menu],
|
|
4057
|
+
options: options[menu],
|
|
4058
|
+
picked: picked[menu],
|
|
4059
|
+
labelOf: (value) => labelOf(menu, value),
|
|
4060
|
+
onChange: (values) => setPicked({ ...picked, [menu]: values })
|
|
4061
|
+
},
|
|
4062
|
+
menu
|
|
4063
|
+
)),
|
|
4064
|
+
Toggle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4065
|
+
Toggle,
|
|
1695
4066
|
{
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
"aria-labelledby": `block-columns-${zone.name}`,
|
|
1702
|
-
$percent: (columns - COLUMNS.min) / (COLUMNS.max - COLUMNS.min) * 100,
|
|
1703
|
-
onChange: (e) => changeColumns(Number(e.target.value))
|
|
4067
|
+
name: `block-fields-${zone.name}`,
|
|
4068
|
+
label: t.showFields,
|
|
4069
|
+
hint: t.showFieldsHint,
|
|
4070
|
+
value: showFields,
|
|
4071
|
+
onChange: changeShowFields
|
|
1704
4072
|
}
|
|
1705
4073
|
),
|
|
1706
|
-
/* @__PURE__ */ (0,
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1711
|
-
import_design_system.Flex,
|
|
1712
|
-
{
|
|
1713
|
-
direction: "column",
|
|
1714
|
-
alignItems: "stretch",
|
|
1715
|
-
gap: 4,
|
|
1716
|
-
style: { overflowY: "auto", maxHeight: "60vh", padding: "4px" },
|
|
1717
|
-
children: groupEntries(entries).map(
|
|
1718
|
-
({ category: name, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
1719
|
-
import_design_system.Flex,
|
|
4074
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", children: [
|
|
4075
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
|
|
4076
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4077
|
+
Slider,
|
|
1720
4078
|
{
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
4079
|
+
type: "range",
|
|
4080
|
+
min: COLUMNS.min,
|
|
4081
|
+
max: COLUMNS.max,
|
|
4082
|
+
step: 1,
|
|
4083
|
+
value: columns,
|
|
4084
|
+
"aria-labelledby": `block-columns-${zone.name}`,
|
|
4085
|
+
$percent: (columns - COLUMNS.min) / (COLUMNS.max - COLUMNS.min) * 100,
|
|
4086
|
+
onChange: (e) => changeColumns(Number(e.target.value))
|
|
4087
|
+
}
|
|
4088
|
+
),
|
|
4089
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", children: columns })
|
|
4090
|
+
] })
|
|
4091
|
+
] }),
|
|
4092
|
+
chips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", "data-testid": "gallery-chips", children: [
|
|
4093
|
+
chips.map(({ menu, value }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
4094
|
+
Chip,
|
|
4095
|
+
{
|
|
4096
|
+
type: "button",
|
|
4097
|
+
"aria-label": t.f("removeFilter", { name: labelOf(menu, value) }),
|
|
4098
|
+
onClick: () => setPicked({ ...picked, [menu]: picked[menu].filter((item) => item !== value) }),
|
|
4099
|
+
children: [
|
|
4100
|
+
labelOf(menu, value),
|
|
4101
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "close", size: 12 })
|
|
4102
|
+
]
|
|
4103
|
+
},
|
|
4104
|
+
`${menu}:${value}`
|
|
4105
|
+
)),
|
|
4106
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
|
|
4107
|
+
] }),
|
|
4108
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
|
|
4109
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
|
|
4110
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4111
|
+
import_design_system2.Flex,
|
|
4112
|
+
{
|
|
4113
|
+
direction: "column",
|
|
4114
|
+
alignItems: "stretch",
|
|
4115
|
+
gap: 4,
|
|
4116
|
+
style: { overflowY: "auto", flex: 1, minHeight: 0, padding: "4px" },
|
|
4117
|
+
children: (view === "recent" ? [{ typology: "recent", entries }] : groupEntries(entries)).map(
|
|
4118
|
+
({ typology, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
4119
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${typology}`, children: `${typology === "recent" ? t.nav.recent : t.typologies[typology] || typology} (${items.length})` }),
|
|
4120
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1735
4121
|
Card,
|
|
1736
4122
|
{
|
|
1737
4123
|
entry,
|
|
1738
4124
|
palette: config.palette,
|
|
1739
4125
|
showFields,
|
|
1740
|
-
|
|
4126
|
+
starred: prefs.starred.includes(entry.uid),
|
|
4127
|
+
active: detail === entry.uid,
|
|
4128
|
+
onOpen: () => setDetail(entry.uid),
|
|
4129
|
+
onInsert: () => select(entry.uid),
|
|
4130
|
+
onStar: () => star(entry.uid)
|
|
1741
4131
|
}
|
|
1742
4132
|
) }, entry.uid)) })
|
|
1743
|
-
]
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
4133
|
+
] }, typology)
|
|
4134
|
+
)
|
|
4135
|
+
}
|
|
4136
|
+
),
|
|
4137
|
+
chosen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
4138
|
+
Magnify,
|
|
4139
|
+
{
|
|
4140
|
+
entry: chosen,
|
|
4141
|
+
palette: config.palette,
|
|
4142
|
+
config,
|
|
4143
|
+
components,
|
|
4144
|
+
get,
|
|
4145
|
+
contentType,
|
|
4146
|
+
locale,
|
|
4147
|
+
cardOf,
|
|
4148
|
+
starred: prefs.starred.includes(chosen.uid),
|
|
4149
|
+
onStar: () => star(chosen.uid),
|
|
4150
|
+
onInsert: () => select(chosen.uid),
|
|
4151
|
+
onClose: () => setDetail(null)
|
|
4152
|
+
},
|
|
4153
|
+
chosen.uid
|
|
1747
4154
|
)
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
4155
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", children: [
|
|
4156
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { children: t.empty }),
|
|
4157
|
+
filtering && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
|
|
4158
|
+
] })
|
|
1752
4159
|
] })
|
|
1753
4160
|
] })
|
|
1754
4161
|
}
|
|
1755
4162
|
);
|
|
1756
4163
|
}
|
|
1757
|
-
var
|
|
4164
|
+
var storage2 = () => {
|
|
1758
4165
|
try {
|
|
1759
4166
|
return window.localStorage;
|
|
1760
4167
|
} catch {
|
|
@@ -1769,12 +4176,12 @@ function useInitialAccordions({
|
|
|
1769
4176
|
contentType,
|
|
1770
4177
|
userId
|
|
1771
4178
|
}) {
|
|
1772
|
-
const applied =
|
|
1773
|
-
const user =
|
|
4179
|
+
const applied = React4.useRef("");
|
|
4180
|
+
const user = React4.useRef(userId);
|
|
1774
4181
|
user.current = userId;
|
|
1775
|
-
const latest =
|
|
4182
|
+
const latest = React4.useRef(zones);
|
|
1776
4183
|
latest.current = zones;
|
|
1777
|
-
|
|
4184
|
+
React4.useEffect(() => {
|
|
1778
4185
|
if (!editor?.enabled || !docKey || applied.current === docKey) return;
|
|
1779
4186
|
if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
|
|
1780
4187
|
applied.current = docKey;
|
|
@@ -1812,55 +4219,74 @@ function useInitialAccordions({
|
|
|
1812
4219
|
});
|
|
1813
4220
|
setAll(
|
|
1814
4221
|
list,
|
|
1815
|
-
initialState(editor, readMemory(
|
|
1816
|
-
|
|
4222
|
+
initialState(editor, readMemory(storage2(), key)) === "open",
|
|
4223
|
+
import_react_dom3.unstable_batchedUpdates
|
|
1817
4224
|
);
|
|
1818
4225
|
}
|
|
1819
4226
|
}, 200);
|
|
1820
4227
|
return stop;
|
|
1821
4228
|
}, [docKey, editor?.enabled, editor?.initialState, contentType]);
|
|
1822
4229
|
}
|
|
1823
|
-
|
|
4230
|
+
var ZONE_ATTR = "data-blockscene-zone-controls";
|
|
4231
|
+
function useLabelAnchor(zone, enabled) {
|
|
4232
|
+
const [el, setEl] = React4.useState(null);
|
|
4233
|
+
React4.useEffect(() => {
|
|
4234
|
+
if (!enabled) return;
|
|
4235
|
+
let frame2 = 0;
|
|
4236
|
+
const sync = () => {
|
|
4237
|
+
const list = findZoneList(zone.label);
|
|
4238
|
+
const row = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim());
|
|
4239
|
+
let anchor = document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`);
|
|
4240
|
+
if (anchor && anchor.parentElement !== row) {
|
|
4241
|
+
anchor.remove();
|
|
4242
|
+
anchor = null;
|
|
4243
|
+
}
|
|
4244
|
+
if (!anchor && row) {
|
|
4245
|
+
anchor = document.createElement("span");
|
|
4246
|
+
anchor.setAttribute(ZONE_ATTR, zone.name);
|
|
4247
|
+
anchor.style.cssText = "display:inline-flex;align-items:center;margin-left:8px";
|
|
4248
|
+
row.appendChild(anchor);
|
|
4249
|
+
}
|
|
4250
|
+
setEl(anchor);
|
|
4251
|
+
};
|
|
4252
|
+
sync();
|
|
4253
|
+
const observer = new MutationObserver(() => {
|
|
4254
|
+
if (!frame2) frame2 = requestAnimationFrame(() => {
|
|
4255
|
+
frame2 = 0;
|
|
4256
|
+
sync();
|
|
4257
|
+
});
|
|
4258
|
+
});
|
|
4259
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
4260
|
+
return () => {
|
|
4261
|
+
observer.disconnect();
|
|
4262
|
+
cancelAnimationFrame(frame2);
|
|
4263
|
+
document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`)?.remove();
|
|
4264
|
+
setEl(null);
|
|
4265
|
+
};
|
|
4266
|
+
}, [zone.name, zone.label, enabled]);
|
|
4267
|
+
return el;
|
|
4268
|
+
}
|
|
4269
|
+
function ZoneControls({ zone, editor, contentType, userId, tools }) {
|
|
1824
4270
|
const t = useMessages();
|
|
1825
|
-
|
|
4271
|
+
const shown = Boolean(zone.count && (editor.showOpenAll || editor.showCloseAll || tools));
|
|
4272
|
+
const anchor = useLabelAnchor(zone, shown);
|
|
4273
|
+
if (!shown || !anchor) return null;
|
|
1826
4274
|
const apply = (open) => {
|
|
1827
4275
|
const list = findZoneList(zone.label);
|
|
1828
|
-
if (list) setAll(list, open,
|
|
4276
|
+
if (list) setAll(list, open, import_react_dom3.unstable_batchedUpdates);
|
|
1829
4277
|
writeMemory(
|
|
1830
|
-
|
|
4278
|
+
storage2(),
|
|
1831
4279
|
memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }),
|
|
1832
4280
|
open ? "open" : "closed"
|
|
1833
4281
|
);
|
|
1834
4282
|
};
|
|
1835
|
-
return
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1843
|
-
import_design_system.Button,
|
|
1844
|
-
{
|
|
1845
|
-
type: "button",
|
|
1846
|
-
variant: "tertiary",
|
|
1847
|
-
size: "S",
|
|
1848
|
-
onClick: () => apply(true),
|
|
1849
|
-
children: t.openAll
|
|
1850
|
-
}
|
|
1851
|
-
),
|
|
1852
|
-
editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1853
|
-
import_design_system.Button,
|
|
1854
|
-
{
|
|
1855
|
-
type: "button",
|
|
1856
|
-
variant: "tertiary",
|
|
1857
|
-
size: "S",
|
|
1858
|
-
onClick: () => apply(false),
|
|
1859
|
-
children: t.closeAll
|
|
1860
|
-
}
|
|
1861
|
-
)
|
|
1862
|
-
]
|
|
1863
|
-
}
|
|
4283
|
+
return (0, import_react_dom3.createPortal)(
|
|
4284
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 1, "data-testid": `block-accordion-controls-${zone.name}`, children: [
|
|
4285
|
+
editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "expand", label: t.openAll, onClick: () => apply(true) }),
|
|
4286
|
+
editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "collapse", label: t.closeAll, onClick: () => apply(false) }),
|
|
4287
|
+
tools
|
|
4288
|
+
] }),
|
|
4289
|
+
anchor
|
|
1864
4290
|
);
|
|
1865
4291
|
}
|
|
1866
4292
|
function Gallery({
|
|
@@ -1873,8 +4299,10 @@ function Gallery({
|
|
|
1873
4299
|
...props
|
|
1874
4300
|
}) {
|
|
1875
4301
|
useInitialAccordions({ zones, editor, docKey, contentType, userId });
|
|
1876
|
-
|
|
1877
|
-
|
|
4302
|
+
const actions = useRowActions({ zones, components: props.components, catalog, form: props.form });
|
|
4303
|
+
React4.useEffect(() => stopAll, [docKey]);
|
|
4304
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
|
|
4305
|
+
editor.showRowThumbnails !== false && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1878
4306
|
RowPreviews,
|
|
1879
4307
|
{
|
|
1880
4308
|
zones,
|
|
@@ -1883,15 +4311,19 @@ function Gallery({
|
|
|
1883
4311
|
Modal: props.Modal
|
|
1884
4312
|
}
|
|
1885
4313
|
),
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
/* @__PURE__ */ (0,
|
|
4314
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RowActions, { zones, actions, Modal: props.Modal }),
|
|
4315
|
+
zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
4316
|
+
zones.length > 1 && !zone.full && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", tag: "h3", children: zone.label }),
|
|
4317
|
+
!zone.full && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneGallery, { zone, contentType, locale: String(docKey || "").split(":").pop(), ...props }),
|
|
4318
|
+
zone.count === 0 && actions?.clip && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneRowTools, { zone, actions }) }),
|
|
4319
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1889
4320
|
ZoneControls,
|
|
1890
4321
|
{
|
|
1891
4322
|
zone,
|
|
1892
4323
|
editor,
|
|
1893
4324
|
contentType,
|
|
1894
|
-
userId
|
|
4325
|
+
userId,
|
|
4326
|
+
tools: actions && actions.editor.clipboard !== false && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneRowTools, { zone, actions })
|
|
1895
4327
|
}
|
|
1896
4328
|
)
|
|
1897
4329
|
] }, zone.name))
|
|
@@ -1899,24 +4331,24 @@ function Gallery({
|
|
|
1899
4331
|
}
|
|
1900
4332
|
|
|
1901
4333
|
// admin/Settings.tsx
|
|
1902
|
-
var
|
|
1903
|
-
var
|
|
1904
|
-
var
|
|
1905
|
-
var
|
|
4334
|
+
var React5 = __toESM(require("react"));
|
|
4335
|
+
var import_design_system3 = require("@strapi/design-system");
|
|
4336
|
+
var import_styled_components4 = __toESM(require("styled-components"));
|
|
4337
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1906
4338
|
var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
|
|
1907
|
-
var Grid =
|
|
1908
|
-
var Card2 =
|
|
4339
|
+
var Grid = import_styled_components4.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
|
|
4340
|
+
var Card2 = import_styled_components4.default.div`
|
|
1909
4341
|
display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
|
|
1910
4342
|
border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral0};
|
|
1911
4343
|
`;
|
|
1912
|
-
var Bar =
|
|
4344
|
+
var Bar = import_styled_components4.default.div`
|
|
1913
4345
|
position: fixed; top: 0; z-index: 4; padding: 12px 32px;
|
|
1914
4346
|
background: ${({ theme }) => theme.colors.neutral100}; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
1915
4347
|
box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
|
|
1916
4348
|
`;
|
|
1917
4349
|
function useMainRect(anchor) {
|
|
1918
|
-
const [rect, setRect] =
|
|
1919
|
-
|
|
4350
|
+
const [rect, setRect] = React5.useState({ left: 0, width: 0 });
|
|
4351
|
+
React5.useEffect(() => {
|
|
1920
4352
|
const read = () => {
|
|
1921
4353
|
let host = document.getElementById("main-content");
|
|
1922
4354
|
for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
|
|
@@ -1929,15 +4361,15 @@ function useMainRect(anchor) {
|
|
|
1929
4361
|
});
|
|
1930
4362
|
return rect;
|
|
1931
4363
|
}
|
|
1932
|
-
var Swatches =
|
|
1933
|
-
var Label =
|
|
4364
|
+
var Swatches = import_styled_components4.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
|
|
4365
|
+
var Label = import_styled_components4.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
|
|
1934
4366
|
function ColorField({ name, label, value, onChange, disabled }) {
|
|
1935
4367
|
const valid = COLOR2.test(value);
|
|
1936
|
-
return /* @__PURE__ */ (0,
|
|
1937
|
-
/* @__PURE__ */ (0,
|
|
1938
|
-
/* @__PURE__ */ (0,
|
|
1939
|
-
/* @__PURE__ */ (0,
|
|
1940
|
-
/* @__PURE__ */ (0,
|
|
4368
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label, { children: [
|
|
4369
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
|
|
4370
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, children: [
|
|
4371
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
|
|
4372
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1941
4373
|
"input",
|
|
1942
4374
|
{
|
|
1943
4375
|
name,
|
|
@@ -1952,23 +4384,151 @@ function ColorField({ name, label, value, onChange, disabled }) {
|
|
|
1952
4384
|
] })
|
|
1953
4385
|
] });
|
|
1954
4386
|
}
|
|
4387
|
+
function TagsField({ name, label, hint, value, onChange, disabled }) {
|
|
4388
|
+
const [text, setText] = React5.useState(value.join(", "));
|
|
4389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label, { children: [
|
|
4390
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
|
|
4391
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { name, value: text, disabled, onChange: (e) => {
|
|
4392
|
+
setText(e.target.value);
|
|
4393
|
+
onChange([...new Set(e.target.value.split(",").map((tag) => tag.replace(/[<>]/g, "").trim().slice(0, 24)).filter(Boolean))].slice(0, 10));
|
|
4394
|
+
}, style: { padding: "6px 8px", border: "1px solid #dcdce4", borderRadius: 4, fontSize: 13 } }),
|
|
4395
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: hint })
|
|
4396
|
+
] });
|
|
4397
|
+
}
|
|
4398
|
+
var FIELD_UID = /^(plugin|global)::[\w.-]+$/;
|
|
4399
|
+
var LAZY_MAX = 20;
|
|
4400
|
+
var parseUids = (text) => [...new Set(text.split(/[\s,]+/).filter(Boolean))];
|
|
4401
|
+
var badUids = (uids = []) => uids.length > LAZY_MAX || uids.some((uid) => !FIELD_UID.test(uid));
|
|
4402
|
+
function UidListField({ TextField: TextField2, value, onChange, ...props }) {
|
|
4403
|
+
const [text, setText] = React5.useState(value.join(", "));
|
|
4404
|
+
React5.useEffect(() => {
|
|
4405
|
+
if (parseUids(text).join() !== value.join()) setText(value.join(", "));
|
|
4406
|
+
}, [value.join()]);
|
|
4407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TextField2, { ...props, value: text, onChange: (v) => {
|
|
4408
|
+
setText(v);
|
|
4409
|
+
onChange(parseUids(v));
|
|
4410
|
+
} });
|
|
4411
|
+
}
|
|
4412
|
+
var SIDEBAR_ICONS = ["text", "tag", "seo", "settings", "image", "link", "palette", "list", "globe", "info"];
|
|
4413
|
+
var SIDEBAR_MAX = 12;
|
|
4414
|
+
var ITEM_LABEL = /^[^<>]{1,40}$/;
|
|
4415
|
+
var badItem = (item) => !ITEM_LABEL.test(String(item.label || "").trim()) || !item.fields?.length;
|
|
4416
|
+
var SYSTEM_FIELDS2 = ["createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
|
|
4417
|
+
var Item = import_styled_components4.default.div`
|
|
4418
|
+
display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
|
|
4419
|
+
border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral100};
|
|
4420
|
+
`;
|
|
4421
|
+
var Checks = import_styled_components4.default.fieldset`
|
|
4422
|
+
display: flex; flex-wrap: wrap; gap: 4px 16px; border: 0; padding: 0; margin: 0; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800};
|
|
4423
|
+
legend { font-size: 12px; font-weight: 600; margin-bottom: 4px; }
|
|
4424
|
+
label { display: inline-flex; align-items: center; gap: 6px; }
|
|
4425
|
+
`;
|
|
4426
|
+
function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
|
|
4427
|
+
const items = entry.sidebar || [];
|
|
4428
|
+
const save = (next) => set("sidebar", next.length ? next : void 0, void 0);
|
|
4429
|
+
const edit = (index, patch) => save(items.map((item, i) => i === index ? { ...item, ...patch } : item));
|
|
4430
|
+
const move = (index, by) => {
|
|
4431
|
+
const next = [...items];
|
|
4432
|
+
[next[index], next[index + by]] = [next[index + by], next[index]];
|
|
4433
|
+
save(next);
|
|
4434
|
+
};
|
|
4435
|
+
const fields = (type.attributes || []).filter((attr) => !SYSTEM_FIELDS2.includes(attr.name));
|
|
4436
|
+
const id = (name, index) => `sidebar-${name}-${type.uid}${index === void 0 ? "" : `-${index}`}`;
|
|
4437
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
|
|
4438
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
|
|
4439
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
|
|
4440
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { maxWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4441
|
+
SelectField2,
|
|
4442
|
+
{
|
|
4443
|
+
name: id("position"),
|
|
4444
|
+
label: t.sidebarPosition,
|
|
4445
|
+
value: entry.sidebarPosition || "left",
|
|
4446
|
+
disabled,
|
|
4447
|
+
options: ["left", "right", "bottom"].map((value) => ({ value, label: t.positions[value] })),
|
|
4448
|
+
onChange: (v) => set("sidebarPosition", v, "left")
|
|
4449
|
+
}
|
|
4450
|
+
) }),
|
|
4451
|
+
items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Item, { "data-testid": id("item", index), children: [
|
|
4452
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
|
|
4453
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
|
|
4454
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 180 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4455
|
+
SelectField2,
|
|
4456
|
+
{
|
|
4457
|
+
name: id("icon", index),
|
|
4458
|
+
label: t.sidebarIcon,
|
|
4459
|
+
value: item.icon || "none",
|
|
4460
|
+
disabled,
|
|
4461
|
+
options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: value, size: 16 }) }))],
|
|
4462
|
+
onChange: (v) => edit(index, { icon: v === "none" ? void 0 : v })
|
|
4463
|
+
}
|
|
4464
|
+
) }),
|
|
4465
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 160 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4466
|
+
SelectField2,
|
|
4467
|
+
{
|
|
4468
|
+
name: id("open", index),
|
|
4469
|
+
label: t.sidebarOpens,
|
|
4470
|
+
value: item.open,
|
|
4471
|
+
disabled,
|
|
4472
|
+
options: ["drawer", "modal"].map((value) => ({ value, label: t.opens[value] })),
|
|
4473
|
+
onChange: (v) => edit(index, { open: v })
|
|
4474
|
+
}
|
|
4475
|
+
) }),
|
|
4476
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 1, paddingBottom: 1, children: [
|
|
4477
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
|
|
4478
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items.length - 1, onClick: () => move(index, 1) }),
|
|
4479
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items.filter((_, i) => i !== index)) })
|
|
4480
|
+
] })
|
|
4481
|
+
] }),
|
|
4482
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Checks, { disabled, children: [
|
|
4483
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: t.sidebarFields }),
|
|
4484
|
+
fields.map((attr) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
|
|
4485
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4486
|
+
"input",
|
|
4487
|
+
{
|
|
4488
|
+
type: "checkbox",
|
|
4489
|
+
name: id(`field-${attr.name}`, index),
|
|
4490
|
+
checked: item.fields.includes(attr.name),
|
|
4491
|
+
onChange: (e) => edit(index, { fields: e.target.checked ? [...item.fields, attr.name] : item.fields.filter((name) => name !== attr.name) })
|
|
4492
|
+
}
|
|
4493
|
+
),
|
|
4494
|
+
attr.name
|
|
4495
|
+
] }, attr.name))
|
|
4496
|
+
] }),
|
|
4497
|
+
badItem(item) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
|
|
4498
|
+
] }, index)),
|
|
4499
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, alignItems: "center", children: [
|
|
4500
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4501
|
+
import_design_system3.Button,
|
|
4502
|
+
{
|
|
4503
|
+
variant: "secondary",
|
|
4504
|
+
size: "S",
|
|
4505
|
+
disabled: disabled || items.length >= SIDEBAR_MAX,
|
|
4506
|
+
"data-testid": id("add"),
|
|
4507
|
+
onClick: () => save([...items, { label: "", open: "drawer", fields: [] }]),
|
|
4508
|
+
children: t.sidebarAdd
|
|
4509
|
+
}
|
|
4510
|
+
),
|
|
4511
|
+
items.length >= SIDEBAR_MAX && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
|
|
4512
|
+
] })
|
|
4513
|
+
] });
|
|
4514
|
+
}
|
|
1955
4515
|
var permissions = { read: [{ action: "plugin::blockscene.settings.read", subject: null }], update: [{ action: "plugin::blockscene.settings.update", subject: null }] };
|
|
1956
|
-
function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: MediaPicker2, ToggleField: ToggleField2, SelectField: SelectField2, TextField, previewSupported = false }) {
|
|
4516
|
+
function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: MediaPicker2, ToggleField: ToggleField2, SelectField: SelectField2, TextField: TextField2, previewSupported = false }) {
|
|
1957
4517
|
const t = useMessages();
|
|
1958
|
-
const { get, put } = useClient();
|
|
4518
|
+
const { get, put, del } = useClient();
|
|
1959
4519
|
const { canRead, canUpdate, isLoading } = usePermissions2();
|
|
1960
|
-
const [data, setData] =
|
|
1961
|
-
const [catalog, setCatalog] =
|
|
1962
|
-
const [settings, setSettings] =
|
|
1963
|
-
const [media, setMedia] =
|
|
1964
|
-
const [sources, setSources] =
|
|
1965
|
-
const [dirty, setDirty] =
|
|
1966
|
-
const [saving, setSaving] =
|
|
1967
|
-
const [status, setStatus] =
|
|
1968
|
-
const [failed, setFailed] =
|
|
1969
|
-
const [filter, setFilter] =
|
|
1970
|
-
const [picking, setPicking] =
|
|
1971
|
-
|
|
4520
|
+
const [data, setData] = React5.useState(null);
|
|
4521
|
+
const [catalog, setCatalog] = React5.useState(null);
|
|
4522
|
+
const [settings, setSettings] = React5.useState(null);
|
|
4523
|
+
const [media, setMedia] = React5.useState({});
|
|
4524
|
+
const [sources, setSources] = React5.useState({});
|
|
4525
|
+
const [dirty, setDirty] = React5.useState(false);
|
|
4526
|
+
const [saving, setSaving] = React5.useState(false);
|
|
4527
|
+
const [status, setStatus] = React5.useState("");
|
|
4528
|
+
const [failed, setFailed] = React5.useState(false);
|
|
4529
|
+
const [filter, setFilter] = React5.useState("");
|
|
4530
|
+
const [picking, setPicking] = React5.useState(null);
|
|
4531
|
+
React5.useEffect(() => {
|
|
1972
4532
|
if (!canRead || isLoading) return;
|
|
1973
4533
|
let active = true;
|
|
1974
4534
|
Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
|
|
@@ -1989,7 +4549,10 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
1989
4549
|
setDirty(true);
|
|
1990
4550
|
setStatus("");
|
|
1991
4551
|
};
|
|
1992
|
-
const
|
|
4552
|
+
const badColor = settings && (Object.values(settings.palette).some((value) => !COLOR2.test(value)) || [settings.editor.previewUrl, settings.editor.blockPreviewUrl].some((url) => url && !/^https?:\/\/\S+$/.test(url)));
|
|
4553
|
+
const badSidebar = settings && Object.values(settings.contentTypes || {}).some((entry) => (entry.sidebar || []).some(badItem));
|
|
4554
|
+
const badLazy = settings && badUids(settings.editor.lazyFields);
|
|
4555
|
+
const invalid = badColor || badSidebar || badLazy;
|
|
1993
4556
|
const save = async () => {
|
|
1994
4557
|
if (!settings || invalid || !canUpdate) return;
|
|
1995
4558
|
setSaving(true);
|
|
@@ -2007,6 +4570,31 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2007
4570
|
setSaving(false);
|
|
2008
4571
|
}
|
|
2009
4572
|
};
|
|
4573
|
+
const restore = async () => {
|
|
4574
|
+
if (!canUpdate || !window.confirm(data.projectDefaults ? t.restoreProjectConfirm : t.resetAllConfirm)) return;
|
|
4575
|
+
setSaving(true);
|
|
4576
|
+
setStatus("");
|
|
4577
|
+
try {
|
|
4578
|
+
const { data: fresh } = await del("/blockscene/settings");
|
|
4579
|
+
setSettings(fresh);
|
|
4580
|
+
setDirty(false);
|
|
4581
|
+
setStatus(t.restored);
|
|
4582
|
+
const refreshed = await get("/blockscene/settings");
|
|
4583
|
+
setMedia(refreshed.data.media || {});
|
|
4584
|
+
} catch {
|
|
4585
|
+
setStatus(t.saveFailed);
|
|
4586
|
+
} finally {
|
|
4587
|
+
setSaving(false);
|
|
4588
|
+
}
|
|
4589
|
+
};
|
|
4590
|
+
const setComponent = (uid, key, value) => update((s) => {
|
|
4591
|
+
const next = { ...s.components[uid] };
|
|
4592
|
+
if (value === void 0) delete next[key];
|
|
4593
|
+
else next[key] = value;
|
|
4594
|
+
if (Object.keys(next).length) s.components[uid] = next;
|
|
4595
|
+
else delete s.components[uid];
|
|
4596
|
+
return s;
|
|
4597
|
+
});
|
|
2010
4598
|
const editor = settings?.editor || {};
|
|
2011
4599
|
const components = (data?.components || []).filter((c) => `${c.displayName} ${c.uid}`.toLocaleLowerCase().includes(filter.trim().toLocaleLowerCase()));
|
|
2012
4600
|
const sourceOf = (uid, manual) => {
|
|
@@ -2016,35 +4604,36 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2016
4604
|
return index === 0 && manual ? t.manual : t.automatic;
|
|
2017
4605
|
};
|
|
2018
4606
|
const ready = !isLoading && canRead && !failed && settings && catalog;
|
|
2019
|
-
const header =
|
|
2020
|
-
const [floating, setFloating] =
|
|
4607
|
+
const header = React5.useRef(null);
|
|
4608
|
+
const [floating, setFloating] = React5.useState(false);
|
|
2021
4609
|
const main = useMainRect(header);
|
|
2022
|
-
|
|
4610
|
+
React5.useEffect(() => {
|
|
2023
4611
|
const el = header.current;
|
|
2024
4612
|
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
2025
4613
|
const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
|
|
2026
4614
|
observer.observe(el);
|
|
2027
4615
|
return () => observer.disconnect();
|
|
2028
4616
|
}, [ready]);
|
|
2029
|
-
const controls = (suffix) => ready && /* @__PURE__ */ (0,
|
|
2030
|
-
/* @__PURE__ */ (0,
|
|
2031
|
-
/* @__PURE__ */ (0,
|
|
4617
|
+
const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
|
|
4618
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
|
|
4619
|
+
!suffix && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
|
|
4620
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
|
|
2032
4621
|
] });
|
|
2033
|
-
return /* @__PURE__ */ (0,
|
|
2034
|
-
/* @__PURE__ */ (0,
|
|
2035
|
-
/* @__PURE__ */ (0,
|
|
4622
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
|
|
4623
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
|
|
4624
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
|
|
2036
4625
|
controls("")
|
|
2037
4626
|
] }) }),
|
|
2038
|
-
floating && main.width > 0 && /* @__PURE__ */ (0,
|
|
2039
|
-
/* @__PURE__ */ (0,
|
|
4627
|
+
floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
|
|
4628
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
|
|
2040
4629
|
controls("-floating")
|
|
2041
4630
|
] }) }),
|
|
2042
|
-
/* @__PURE__ */ (0,
|
|
2043
|
-
isLoading ? /* @__PURE__ */ (0,
|
|
2044
|
-
data.disabled && /* @__PURE__ */ (0,
|
|
2045
|
-
/* @__PURE__ */ (0,
|
|
2046
|
-
/* @__PURE__ */ (0,
|
|
2047
|
-
/* @__PURE__ */ (0,
|
|
4631
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { textColor: "neutral600", children: t.settingsIntro }),
|
|
4632
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
4633
|
+
data.disabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
|
|
4634
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
4635
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.palette }),
|
|
4636
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2048
4637
|
ColorField,
|
|
2049
4638
|
{
|
|
2050
4639
|
name: `palette-${key}`,
|
|
@@ -2058,33 +4647,37 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2058
4647
|
},
|
|
2059
4648
|
key
|
|
2060
4649
|
)) }),
|
|
2061
|
-
|
|
2062
|
-
/* @__PURE__ */ (0,
|
|
2063
|
-
/* @__PURE__ */ (0,
|
|
2064
|
-
/* @__PURE__ */ (0,
|
|
2065
|
-
/* @__PURE__ */ (0,
|
|
4650
|
+
badColor && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
|
|
4651
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
|
|
4652
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", gap: 1, children: [
|
|
4653
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Wireframe, { template, palette: settings.palette }) }),
|
|
4654
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
|
|
2066
4655
|
] }, template)) }),
|
|
2067
|
-
/* @__PURE__ */ (0,
|
|
4656
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
|
|
2068
4657
|
s.palette = { ...DEFAULT_PALETTE };
|
|
2069
4658
|
return s;
|
|
2070
4659
|
}), children: t.resetPalette }) })
|
|
2071
4660
|
] }) }),
|
|
2072
|
-
/* @__PURE__ */ (0,
|
|
2073
|
-
/* @__PURE__ */ (0,
|
|
2074
|
-
/* @__PURE__ */ (0,
|
|
4661
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
4662
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.editor }),
|
|
4663
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
2075
4664
|
s.editor.enabled = v;
|
|
2076
4665
|
return s;
|
|
2077
4666
|
}) }),
|
|
2078
|
-
/* @__PURE__ */ (0,
|
|
2079
|
-
/* @__PURE__ */ (0,
|
|
4667
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
|
|
4668
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
2080
4669
|
s.editor.showOpenAll = v;
|
|
2081
4670
|
return s;
|
|
2082
4671
|
}) }),
|
|
2083
|
-
/* @__PURE__ */ (0,
|
|
4672
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
2084
4673
|
s.editor.showCloseAll = v;
|
|
2085
4674
|
return s;
|
|
2086
4675
|
}) }),
|
|
2087
|
-
/* @__PURE__ */ (0,
|
|
4676
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
4677
|
+
s.editor.showRowThumbnails = v;
|
|
4678
|
+
return s;
|
|
4679
|
+
}) }),
|
|
4680
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2088
4681
|
SelectField2,
|
|
2089
4682
|
{
|
|
2090
4683
|
name: "editor-initialState",
|
|
@@ -2098,10 +4691,25 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2098
4691
|
})
|
|
2099
4692
|
}
|
|
2100
4693
|
),
|
|
2101
|
-
/* @__PURE__ */ (0,
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
4694
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
|
|
4695
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4696
|
+
TextField2,
|
|
4697
|
+
{
|
|
4698
|
+
name: "editor-blockPreviewUrl",
|
|
4699
|
+
label: t.blockPreviewUrl,
|
|
4700
|
+
value: editor.blockPreviewUrl || "",
|
|
4701
|
+
disabled: !canUpdate || saving,
|
|
4702
|
+
placeholder: "http://localhost:3000/block-preview/{name}/{variant}",
|
|
4703
|
+
onChange: (v) => update((s) => {
|
|
4704
|
+
s.editor.blockPreviewUrl = v.trim();
|
|
4705
|
+
return s;
|
|
4706
|
+
})
|
|
4707
|
+
}
|
|
4708
|
+
),
|
|
4709
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
|
|
4710
|
+
previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
4711
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4712
|
+
TextField2,
|
|
2105
4713
|
{
|
|
2106
4714
|
name: "editor-previewUrl",
|
|
2107
4715
|
label: t.previewUrl,
|
|
@@ -2114,8 +4722,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2114
4722
|
})
|
|
2115
4723
|
}
|
|
2116
4724
|
),
|
|
2117
|
-
/* @__PURE__ */ (0,
|
|
2118
|
-
/* @__PURE__ */ (0,
|
|
4725
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
|
|
4726
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2119
4727
|
SelectField2,
|
|
2120
4728
|
{
|
|
2121
4729
|
name: "editor-previewMode",
|
|
@@ -2129,26 +4737,119 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2129
4737
|
})
|
|
2130
4738
|
}
|
|
2131
4739
|
),
|
|
2132
|
-
/* @__PURE__ */ (0,
|
|
2133
|
-
|
|
2134
|
-
|
|
4740
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
|
|
4741
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
4742
|
+
s.editor.lazyEditors = v;
|
|
4743
|
+
return s;
|
|
4744
|
+
}) }),
|
|
4745
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4746
|
+
UidListField,
|
|
4747
|
+
{
|
|
4748
|
+
TextField: TextField2,
|
|
4749
|
+
name: "editor-lazyFields",
|
|
4750
|
+
label: t.lazyFields,
|
|
4751
|
+
value: editor.lazyFields || [],
|
|
4752
|
+
disabled: !canUpdate || saving || editor.lazyEditors === false,
|
|
4753
|
+
placeholder: "plugin::ckeditor5.CKEditor",
|
|
4754
|
+
onChange: (uids) => update((s) => {
|
|
4755
|
+
s.editor.lazyFields = uids;
|
|
4756
|
+
return s;
|
|
4757
|
+
})
|
|
4758
|
+
}
|
|
4759
|
+
),
|
|
4760
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
|
|
4761
|
+
data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
4762
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
2135
4763
|
s.editor.blockPreviewInForm = v;
|
|
2136
4764
|
return s;
|
|
2137
4765
|
}) }),
|
|
2138
|
-
/* @__PURE__ */ (0,
|
|
4766
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
|
|
2139
4767
|
] })
|
|
2140
|
-
] }) : /* @__PURE__ */ (0,
|
|
4768
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
|
|
4769
|
+
] }) }),
|
|
4770
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
|
|
4771
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
|
|
4772
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
4773
|
+
s.editor.confirmDelete = v;
|
|
4774
|
+
return s;
|
|
4775
|
+
}) }),
|
|
4776
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
4777
|
+
s.editor.duplicate = v;
|
|
4778
|
+
return s;
|
|
4779
|
+
}) }),
|
|
4780
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
4781
|
+
s.editor.clipboard = v;
|
|
4782
|
+
return s;
|
|
4783
|
+
}) }),
|
|
4784
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4785
|
+
SelectField2,
|
|
4786
|
+
{
|
|
4787
|
+
name: "editor-hiddenBlocks",
|
|
4788
|
+
label: t.hiddenBlocks,
|
|
4789
|
+
value: editor.hiddenBlocks || "strip",
|
|
4790
|
+
disabled: !canUpdate || saving || !data.hiddenAttribute,
|
|
4791
|
+
options: ["strip", "flag", "off"].map((value) => ({ value, label: t.hiddenModes[value] })),
|
|
4792
|
+
onChange: (v) => update((s) => {
|
|
4793
|
+
s.editor.hiddenBlocks = v;
|
|
4794
|
+
return s;
|
|
4795
|
+
})
|
|
4796
|
+
}
|
|
4797
|
+
),
|
|
4798
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
|
|
2141
4799
|
] }) }),
|
|
2142
|
-
/* @__PURE__ */ (0,
|
|
2143
|
-
/* @__PURE__ */ (0,
|
|
2144
|
-
/* @__PURE__ */ (0,
|
|
2145
|
-
|
|
2146
|
-
|
|
4800
|
+
(data.contentTypes || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
|
|
4801
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.contentTypes }),
|
|
4802
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
|
|
4803
|
+
data.contentTypes.map((type) => {
|
|
4804
|
+
const entry = settings.contentTypes?.[type.uid] || {};
|
|
4805
|
+
const set = (key, value, fallback) => update((s) => {
|
|
4806
|
+
const next = { ...s.contentTypes?.[type.uid] || {} };
|
|
4807
|
+
if (value === fallback) delete next[key];
|
|
4808
|
+
else next[key] = value;
|
|
4809
|
+
s.contentTypes = { ...s.contentTypes || {} };
|
|
4810
|
+
if (Object.keys(next).length) s.contentTypes[type.uid] = next;
|
|
4811
|
+
else delete s.contentTypes[type.uid];
|
|
4812
|
+
return s;
|
|
4813
|
+
});
|
|
4814
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
4815
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
|
|
4816
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 220 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4817
|
+
ToggleField2,
|
|
4818
|
+
{
|
|
4819
|
+
name: `type-enabled-${type.uid}`,
|
|
4820
|
+
label: type.displayName,
|
|
4821
|
+
value: entry.enabled !== false,
|
|
4822
|
+
disabled: !canUpdate || saving,
|
|
4823
|
+
onChange: (v) => set("enabled", v, true)
|
|
4824
|
+
}
|
|
4825
|
+
) }),
|
|
4826
|
+
previewSupported && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4827
|
+
SelectField2,
|
|
4828
|
+
{
|
|
4829
|
+
name: `type-mode-${type.uid}`,
|
|
4830
|
+
label: t.typeMode,
|
|
4831
|
+
value: entry.previewMode || "default",
|
|
4832
|
+
disabled: !canUpdate || saving || entry.enabled === false,
|
|
4833
|
+
options: [{ value: "default", label: t.f("modeDefault", { mode: t.modes[editor.previewMode || "form"] }) }, ...["form", "split", "preview"].map((value) => ({ value, label: t.modes[value] }))],
|
|
4834
|
+
onChange: (v) => set("previewMode", v, "default")
|
|
4835
|
+
}
|
|
4836
|
+
) })
|
|
4837
|
+
] }),
|
|
4838
|
+
previewSupported && entry.enabled !== false && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SidebarEditor, { type, entry, set, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 })
|
|
4839
|
+
] }, type.uid);
|
|
4840
|
+
}),
|
|
4841
|
+
badSidebar && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
|
|
4842
|
+
] }) }),
|
|
4843
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
4844
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.components }),
|
|
4845
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
|
|
4846
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
|
|
4847
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
|
|
2147
4848
|
const entry = settings.components[component.uid] || {};
|
|
2148
4849
|
const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
|
|
2149
4850
|
const candidates = candidatesFor(component.uid, meta, catalog);
|
|
2150
|
-
return /* @__PURE__ */ (0,
|
|
2151
|
-
/* @__PURE__ */ (0,
|
|
4851
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
|
|
4852
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2152
4853
|
Thumb,
|
|
2153
4854
|
{
|
|
2154
4855
|
candidates,
|
|
@@ -2159,23 +4860,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2159
4860
|
onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
|
|
2160
4861
|
}
|
|
2161
4862
|
),
|
|
2162
|
-
/* @__PURE__ */ (0,
|
|
2163
|
-
/* @__PURE__ */ (0,
|
|
2164
|
-
/* @__PURE__ */ (0,
|
|
4863
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
|
|
4864
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
|
|
4865
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
2165
4866
|
component.uid,
|
|
2166
4867
|
" \xB7 ",
|
|
2167
4868
|
component.category
|
|
2168
4869
|
] }),
|
|
2169
|
-
/* @__PURE__ */ (0,
|
|
4870
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
|
|
2170
4871
|
t.source,
|
|
2171
4872
|
": ",
|
|
2172
4873
|
sourceOf(component.uid, Boolean(meta.manualImage)),
|
|
2173
4874
|
meta.manualName ? ` (${meta.manualName})` : ""
|
|
2174
4875
|
] }),
|
|
2175
|
-
meta.manualMissing && /* @__PURE__ */ (0,
|
|
2176
|
-
/* @__PURE__ */ (0,
|
|
2177
|
-
/* @__PURE__ */ (0,
|
|
2178
|
-
entry.mediaId && /* @__PURE__ */ (0,
|
|
4876
|
+
meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
|
|
4877
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, wrap: "wrap", children: [
|
|
4878
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
|
|
4879
|
+
entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
|
|
2179
4880
|
update((s) => {
|
|
2180
4881
|
delete s.components[component.uid]?.mediaId;
|
|
2181
4882
|
if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
|
|
@@ -2188,7 +4889,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2188
4889
|
});
|
|
2189
4890
|
}, children: t.useAutomatic })
|
|
2190
4891
|
] }),
|
|
2191
|
-
/* @__PURE__ */ (0,
|
|
4892
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2192
4893
|
SelectField2,
|
|
2193
4894
|
{
|
|
2194
4895
|
name: `template-${component.uid}`,
|
|
@@ -2201,12 +4902,34 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2201
4902
|
return s;
|
|
2202
4903
|
})
|
|
2203
4904
|
}
|
|
4905
|
+
),
|
|
4906
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4907
|
+
SelectField2,
|
|
4908
|
+
{
|
|
4909
|
+
name: `typology-${component.uid}`,
|
|
4910
|
+
label: t.typology,
|
|
4911
|
+
value: entry.typology || "auto",
|
|
4912
|
+
disabled: !canUpdate || saving,
|
|
4913
|
+
options: [{ value: "auto", label: t.f("typologyAuto", { name: t.typologies[component.typology] || component.typology }) }, ...(data.typologies || []).map((value) => ({ value, label: t.typologies[value] }))],
|
|
4914
|
+
onChange: (v) => setComponent(component.uid, "typology", v === "auto" ? void 0 : v)
|
|
4915
|
+
}
|
|
4916
|
+
),
|
|
4917
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
4918
|
+
TagsField,
|
|
4919
|
+
{
|
|
4920
|
+
name: `tags-${component.uid}`,
|
|
4921
|
+
label: t.tags,
|
|
4922
|
+
hint: t.tagsHelp,
|
|
4923
|
+
value: entry.tags || [],
|
|
4924
|
+
disabled: !canUpdate || saving,
|
|
4925
|
+
onChange: (tags) => setComponent(component.uid, "tags", tags.length ? tags : void 0)
|
|
4926
|
+
}
|
|
2204
4927
|
)
|
|
2205
4928
|
] })
|
|
2206
4929
|
] }, component.uid);
|
|
2207
4930
|
}) })
|
|
2208
4931
|
] }) }),
|
|
2209
|
-
picking && /* @__PURE__ */ (0,
|
|
4932
|
+
picking && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
|
|
2210
4933
|
const uid = picking;
|
|
2211
4934
|
setPicking(null);
|
|
2212
4935
|
if (!asset?.id) return;
|
|
@@ -2219,7 +4942,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
|
|
|
2219
4942
|
] })
|
|
2220
4943
|
] }) });
|
|
2221
4944
|
}
|
|
2222
|
-
function register(app,
|
|
4945
|
+
function register(app, Component2, to) {
|
|
2223
4946
|
app.createSettingSection(
|
|
2224
4947
|
{ id: "blockscene", intlLabel: { id: "blockscene.title", defaultMessage: "Blockscene" } },
|
|
2225
4948
|
[{
|
|
@@ -2228,17 +4951,17 @@ function register(app, Component, to) {
|
|
|
2228
4951
|
intlLabel: { id: "blockscene.settings", defaultMessage: "Gallery" },
|
|
2229
4952
|
// Module shape: older Strapi 4 (e.g. 4.11) only reads `.default` from the loader result.
|
|
2230
4953
|
// Not an `async` function: Strapi 5 warns on AsyncFunction loaders.
|
|
2231
|
-
Component: () => Promise.resolve({ default:
|
|
4954
|
+
Component: () => Promise.resolve({ default: Component2 }),
|
|
2232
4955
|
permissions: permissions.read
|
|
2233
4956
|
}]
|
|
2234
4957
|
);
|
|
2235
4958
|
}
|
|
2236
4959
|
|
|
2237
4960
|
// admin/catalog.ts
|
|
2238
|
-
var
|
|
4961
|
+
var React6 = __toESM(require("react"));
|
|
2239
4962
|
function useCatalog(get) {
|
|
2240
|
-
const [catalog, setCatalog] =
|
|
2241
|
-
|
|
4963
|
+
const [catalog, setCatalog] = React6.useState(null);
|
|
4964
|
+
React6.useEffect(() => {
|
|
2242
4965
|
let active = true;
|
|
2243
4966
|
get("/blockscene/catalog").then(({ data }) => {
|
|
2244
4967
|
if (active) setCatalog(data);
|
|
@@ -2252,23 +4975,63 @@ function useCatalog(get) {
|
|
|
2252
4975
|
return catalog;
|
|
2253
4976
|
}
|
|
2254
4977
|
|
|
4978
|
+
// admin/Guard.tsx
|
|
4979
|
+
var React7 = __toESM(require("react"));
|
|
4980
|
+
var import_design_system4 = require("@strapi/design-system");
|
|
4981
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
4982
|
+
var Notice = () => {
|
|
4983
|
+
const t = useMessages();
|
|
4984
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system4.Box, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "warning700", role: "alert", children: t.crashed }) });
|
|
4985
|
+
};
|
|
4986
|
+
var Guard = class extends React7.Component {
|
|
4987
|
+
constructor() {
|
|
4988
|
+
super(...arguments);
|
|
4989
|
+
__publicField(this, "state", { failed: false });
|
|
4990
|
+
}
|
|
4991
|
+
static getDerivedStateFromError() {
|
|
4992
|
+
return { failed: true };
|
|
4993
|
+
}
|
|
4994
|
+
componentDidCatch(error) {
|
|
4995
|
+
console.error("[blockscene] disabled for this view after an error:", error);
|
|
4996
|
+
}
|
|
4997
|
+
render() {
|
|
4998
|
+
return this.state.failed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Notice, {}) : this.props.children;
|
|
4999
|
+
}
|
|
5000
|
+
};
|
|
5001
|
+
|
|
2255
5002
|
// admin/strapi4.tsx
|
|
2256
|
-
var
|
|
2257
|
-
function Modal({ open, onOpenChange, trigger, title, children }) {
|
|
2258
|
-
const id =
|
|
2259
|
-
return /* @__PURE__ */ (0,
|
|
5003
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
5004
|
+
function Modal({ open, onOpenChange, trigger, title, children, width = "80vw" }) {
|
|
5005
|
+
const id = React8.useId();
|
|
5006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
|
|
2260
5007
|
trigger,
|
|
2261
|
-
open && /* @__PURE__ */ (0,
|
|
2262
|
-
/* @__PURE__ */ (0,
|
|
2263
|
-
/* @__PURE__ */ (0,
|
|
5008
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_design_system5.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
|
|
5009
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.Typography, { id, variant: "beta", children: title }) }),
|
|
5010
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.ModalBody, { children })
|
|
2264
5011
|
] })
|
|
2265
5012
|
] });
|
|
2266
5013
|
}
|
|
5014
|
+
function useRowForm(c, components) {
|
|
5015
|
+
const toggleNotification = (0, import_helper_plugin.useNotification)();
|
|
5016
|
+
const latest = React8.useRef(c.modifiedData);
|
|
5017
|
+
latest.current = c.modifiedData;
|
|
5018
|
+
if (typeof c.onChange !== "function") return null;
|
|
5019
|
+
return {
|
|
5020
|
+
model: c.slug,
|
|
5021
|
+
locale: c.initialData?.locale || void 0,
|
|
5022
|
+
rows: (zone) => Array.isArray(latest.current?.[zone]) ? latest.current[zone] : [],
|
|
5023
|
+
setRows: (zone, rows) => c.onChange({ target: { name: zone, value: rows } }),
|
|
5024
|
+
keys: (rows, _at, n) => integerKeys(rows, n),
|
|
5025
|
+
notify: (type, message) => toggleNotification({ type, message }),
|
|
5026
|
+
prepare: async (rows) => rows.map((row) => cloneRow(row, components))
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
2267
5029
|
function Picker() {
|
|
2268
5030
|
const c = (0, import_helper_plugin.useCMEditViewDataManager)();
|
|
2269
|
-
const { get } = (0, import_helper_plugin.useFetchClient)();
|
|
5031
|
+
const { get, put } = (0, import_helper_plugin.useFetchClient)();
|
|
2270
5032
|
const catalog = useCatalog(get);
|
|
2271
5033
|
const components = c.allLayoutData?.components || {};
|
|
5034
|
+
const form = useRowForm(c, components);
|
|
2272
5035
|
const schema = c.layout || c.allLayoutData?.contentType;
|
|
2273
5036
|
const allowed = (c.isCreatingEntry ? c.createActionAllowedFields : c.updateActionAllowedFields) || [];
|
|
2274
5037
|
const zones = editableZones(
|
|
@@ -2299,9 +5062,9 @@ function Picker() {
|
|
|
2299
5062
|
);
|
|
2300
5063
|
return true;
|
|
2301
5064
|
};
|
|
2302
|
-
if (!catalog?.editor?.enabled) return null;
|
|
5065
|
+
if (!catalog?.editor?.enabled || catalog.contentTypes?.[c.slug]?.enabled === false) return null;
|
|
2303
5066
|
const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
|
|
2304
|
-
return /* @__PURE__ */ (0,
|
|
5067
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2305
5068
|
Gallery,
|
|
2306
5069
|
{
|
|
2307
5070
|
zones,
|
|
@@ -2310,17 +5073,19 @@ function Picker() {
|
|
|
2310
5073
|
Modal,
|
|
2311
5074
|
Toggle: ToggleField,
|
|
2312
5075
|
get,
|
|
5076
|
+
put,
|
|
2313
5077
|
editor: catalog.editor,
|
|
2314
5078
|
catalog,
|
|
2315
5079
|
docKey,
|
|
2316
5080
|
contentType: c.slug,
|
|
2317
|
-
userId: import_helper_plugin.auth.getUserInfo?.()?.id
|
|
5081
|
+
userId: import_helper_plugin.auth.getUserInfo?.()?.id,
|
|
5082
|
+
form
|
|
2318
5083
|
}
|
|
2319
5084
|
);
|
|
2320
5085
|
}
|
|
2321
|
-
var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0,
|
|
2322
|
-
/* @__PURE__ */ (0,
|
|
2323
|
-
|
|
5086
|
+
var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_design_system5.Flex, { gap: 3, children: [
|
|
5087
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5088
|
+
import_design_system5.Switch,
|
|
2324
5089
|
{
|
|
2325
5090
|
name,
|
|
2326
5091
|
"aria-label": label,
|
|
@@ -2329,8 +5094,9 @@ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ *
|
|
|
2329
5094
|
onChange: () => onChange(!value)
|
|
2330
5095
|
}
|
|
2331
5096
|
),
|
|
2332
|
-
/* @__PURE__ */ (0,
|
|
5097
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.Typography, { children: label })
|
|
2333
5098
|
] });
|
|
5099
|
+
var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
|
|
2334
5100
|
var SelectField = ({
|
|
2335
5101
|
name,
|
|
2336
5102
|
label,
|
|
@@ -2338,15 +5104,15 @@ var SelectField = ({
|
|
|
2338
5104
|
onChange,
|
|
2339
5105
|
disabled,
|
|
2340
5106
|
options
|
|
2341
|
-
}) => /* @__PURE__ */ (0,
|
|
2342
|
-
|
|
5107
|
+
}) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
5108
|
+
import_design_system5.SingleSelect,
|
|
2343
5109
|
{
|
|
2344
5110
|
name,
|
|
2345
5111
|
label,
|
|
2346
5112
|
value,
|
|
2347
5113
|
disabled,
|
|
2348
5114
|
onChange: (v) => onChange(String(v)),
|
|
2349
|
-
children: options.map((o) => /* @__PURE__ */ (0,
|
|
5115
|
+
children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.SingleSelectOption, { value: o.value, children: o.label }, o.value))
|
|
2350
5116
|
}
|
|
2351
5117
|
);
|
|
2352
5118
|
function MediaPicker({ onClose, onSelect }) {
|
|
@@ -2356,7 +5122,7 @@ function MediaPicker({ onClose, onSelect }) {
|
|
|
2356
5122
|
onClose();
|
|
2357
5123
|
return null;
|
|
2358
5124
|
}
|
|
2359
|
-
return /* @__PURE__ */ (0,
|
|
5125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2360
5126
|
Dialog,
|
|
2361
5127
|
{
|
|
2362
5128
|
onClose,
|
|
@@ -2373,7 +5139,7 @@ function usePermissions() {
|
|
|
2373
5139
|
isLoading
|
|
2374
5140
|
};
|
|
2375
5141
|
}
|
|
2376
|
-
var SettingsPage = () => /* @__PURE__ */ (0,
|
|
5142
|
+
var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2377
5143
|
Settings,
|
|
2378
5144
|
{
|
|
2379
5145
|
useClient: import_helper_plugin.useFetchClient,
|
|
@@ -2381,9 +5147,10 @@ var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
|
2381
5147
|
MediaPicker,
|
|
2382
5148
|
ToggleField,
|
|
2383
5149
|
SelectField,
|
|
5150
|
+
TextField,
|
|
2384
5151
|
previewSupported: false
|
|
2385
5152
|
}
|
|
2386
|
-
);
|
|
5153
|
+
) });
|
|
2387
5154
|
var strapi4_default = {
|
|
2388
5155
|
register(app) {
|
|
2389
5156
|
register(app, SettingsPage, "/settings/blockscene");
|
|
@@ -2393,7 +5160,7 @@ var strapi4_default = {
|
|
|
2393
5160
|
bootstrap(app) {
|
|
2394
5161
|
app.injectContentManagerComponent("editView", "right-links", {
|
|
2395
5162
|
name: "blockscene",
|
|
2396
|
-
Component: Picker
|
|
5163
|
+
Component: () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Picker, {}) })
|
|
2397
5164
|
});
|
|
2398
5165
|
}
|
|
2399
5166
|
};
|