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