@aduptive/strapi-blockscene 1.0.0-alpha.1
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/LICENSE +21 -0
- package/README.md +340 -0
- package/dist/admin.cjs +1838 -0
- package/dist/admin.mjs +1808 -0
- package/dist/server.cjs +419 -0
- package/package.json +67 -0
- package/strapi-admin.js +1 -0
- package/strapi-server.js +1 -0
package/dist/admin.cjs
ADDED
|
@@ -0,0 +1,1838 @@
|
|
|
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 __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
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 __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// admin/strapi4.tsx
|
|
30
|
+
var strapi4_exports = {};
|
|
31
|
+
__export(strapi4_exports, {
|
|
32
|
+
default: () => strapi4_default
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(strapi4_exports);
|
|
35
|
+
var React4 = __toESM(require("react"));
|
|
36
|
+
var import_design_system3 = require("@strapi/design-system");
|
|
37
|
+
var import_helper_plugin = require("@strapi/helper-plugin");
|
|
38
|
+
|
|
39
|
+
// admin/Gallery.tsx
|
|
40
|
+
var React = __toESM(require("react"));
|
|
41
|
+
var import_react_dom = require("react-dom");
|
|
42
|
+
var import_design_system = require("@strapi/design-system");
|
|
43
|
+
var import_styled_components = __toESM(require("styled-components"));
|
|
44
|
+
|
|
45
|
+
// admin/model.mjs
|
|
46
|
+
var import_fractional_indexing = require("fractional-indexing");
|
|
47
|
+
function editableZones(schema, values, canEdit, disabled = false) {
|
|
48
|
+
if (disabled) return [];
|
|
49
|
+
return Object.entries(schema?.attributes || {}).filter(([name, attr]) => attr.type === "dynamiczone" && !attr.conditions && canEdit(name)).map(([name, attr]) => {
|
|
50
|
+
const count = Array.isArray(values?.[name]) ? values[name].length : 0;
|
|
51
|
+
return { name, components: attr.components || [], max: attr.max, count, full: count >= (attr.max ?? Infinity) };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function canInsert(zone, uid, values, components, count = 1) {
|
|
55
|
+
return Boolean(zone?.components.includes(uid) && components[uid] && (Array.isArray(values?.[zone.name]) ? values[zone.name].length : 0) + count <= (zone.max ?? Infinity));
|
|
56
|
+
}
|
|
57
|
+
function candidatesFor(uid, meta = {}, config = {}) {
|
|
58
|
+
const version = config.previewVersion ? `?v=${encodeURIComponent(config.previewVersion)}` : "";
|
|
59
|
+
const base = (config.previewBaseUrl || "/block-previews").replace(/\/$/, "");
|
|
60
|
+
return [meta.manualImage, meta.image, `${base}/${encodeURIComponent(uid)}.webp${version}`].filter(Boolean);
|
|
61
|
+
}
|
|
62
|
+
var SYSTEM_FIELDS = ["id", "documentId", "createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
|
|
63
|
+
var fieldType = (attr) => attr?.type === "customField" ? String(attr.customField || "").includes("CKEditor") ? "richtext" : "customField" : attr?.type || "unknown";
|
|
64
|
+
var fieldsOf = (schema) => Object.entries(schema?.attributes || {}).filter(([name]) => !SYSTEM_FIELDS.includes(name)).map(([name, attr]) => ({ name, type: fieldType(attr) }));
|
|
65
|
+
var categoryOf = (uid, schema, meta = {}) => meta.category || schema?.category || uid.split(".")[0];
|
|
66
|
+
var byCategory = (a, b) => (a === "admin" ? 1 : 0) - (b === "admin" ? 1 : 0) || a.localeCompare(b);
|
|
67
|
+
function entriesFor(zone, components, config, query, category = "all") {
|
|
68
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
69
|
+
return zone.components.flatMap((uid) => {
|
|
70
|
+
const schema = components[uid];
|
|
71
|
+
if (!schema) return [];
|
|
72
|
+
const meta = config.components?.[uid] || {};
|
|
73
|
+
const entry = {
|
|
74
|
+
uid,
|
|
75
|
+
label: meta.label || schema.info?.displayName || uid,
|
|
76
|
+
description: meta.description || schema.info?.description || "",
|
|
77
|
+
category: categoryOf(uid, schema, meta),
|
|
78
|
+
fields: fieldsOf(schema),
|
|
79
|
+
candidates: candidatesFor(uid, meta, config),
|
|
80
|
+
template: meta.template || "generic"
|
|
81
|
+
};
|
|
82
|
+
if (category !== "all" && entry.category !== category) return [];
|
|
83
|
+
return `${entry.label} ${entry.description} ${entry.category} ${uid} ${meta.keywords || ""}`.toLocaleLowerCase().includes(needle) ? [entry] : [];
|
|
84
|
+
}).sort((a, b) => byCategory(a.category, b.category) || a.label.localeCompare(b.label));
|
|
85
|
+
}
|
|
86
|
+
function categoriesFor(zone, components, config) {
|
|
87
|
+
const counts = /* @__PURE__ */ new Map();
|
|
88
|
+
for (const uid of zone.components) {
|
|
89
|
+
const schema = components[uid];
|
|
90
|
+
if (!schema) continue;
|
|
91
|
+
const c = categoryOf(uid, schema, config.components?.[uid] || {});
|
|
92
|
+
counts.set(c, (counts.get(c) || 0) + 1);
|
|
93
|
+
}
|
|
94
|
+
return [...counts.entries()].sort(([a], [b]) => byCategory(a, b));
|
|
95
|
+
}
|
|
96
|
+
function groupEntries(entries) {
|
|
97
|
+
const map = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const entry of entries) map.set(entry.category, [...map.get(entry.category) || [], entry]);
|
|
99
|
+
return [...map.entries()].map(([category, items]) => ({ category, entries: items }));
|
|
100
|
+
}
|
|
101
|
+
function memoryKey({ base = "", userId, contentType, zone }) {
|
|
102
|
+
if (!userId || !contentType || !zone) return null;
|
|
103
|
+
return `blockscene:v1:${base}:${userId}:${contentType}:${zone}`;
|
|
104
|
+
}
|
|
105
|
+
function readMemory(storage2, key) {
|
|
106
|
+
try {
|
|
107
|
+
const value = key && storage2?.getItem(key);
|
|
108
|
+
return value === "open" || value === "closed" ? value : null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function writeMemory(storage2, key, value) {
|
|
114
|
+
try {
|
|
115
|
+
if (key && (value === "open" || value === "closed")) storage2?.setItem(key, value);
|
|
116
|
+
} catch {
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function initialState(editor, remembered) {
|
|
120
|
+
if (editor?.initialState === "open") return "open";
|
|
121
|
+
if (editor?.initialState === "remember") return remembered || "closed";
|
|
122
|
+
return "closed";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// admin/accordions.mjs
|
|
126
|
+
function zoneLists(root = document) {
|
|
127
|
+
return [...root.querySelectorAll("ol[aria-describedby]")].filter((list) => list.querySelector(":scope > li button[aria-expanded]"));
|
|
128
|
+
}
|
|
129
|
+
function findZoneList(label, root = document) {
|
|
130
|
+
const lists = zoneLists(root);
|
|
131
|
+
const text = (list) => (list.parentElement?.textContent || "").trim().toLocaleLowerCase();
|
|
132
|
+
return lists.find((list) => text(list).startsWith(String(label).toLocaleLowerCase())) || (lists.length === 1 ? lists[0] : null);
|
|
133
|
+
}
|
|
134
|
+
function toggles(list) {
|
|
135
|
+
return [...list.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
|
|
136
|
+
}
|
|
137
|
+
function setAll(list, open, batch = (run) => run()) {
|
|
138
|
+
const pending = toggles(list).filter((button) => button.getAttribute("aria-expanded") === "true" !== open);
|
|
139
|
+
if (open) {
|
|
140
|
+
batch(() => {
|
|
141
|
+
for (const button of pending) button.click();
|
|
142
|
+
});
|
|
143
|
+
return Promise.resolve(pending.length);
|
|
144
|
+
}
|
|
145
|
+
const frame = () => new Promise((resolve) => typeof requestAnimationFrame === "function" ? requestAnimationFrame(() => resolve()) : setTimeout(resolve, 16));
|
|
146
|
+
return (async () => {
|
|
147
|
+
let changed = 0;
|
|
148
|
+
for (const button of pending) {
|
|
149
|
+
if (!button.isConnected || button.getAttribute("aria-expanded") !== "true") continue;
|
|
150
|
+
button.click();
|
|
151
|
+
changed++;
|
|
152
|
+
await frame();
|
|
153
|
+
}
|
|
154
|
+
return changed;
|
|
155
|
+
})();
|
|
156
|
+
}
|
|
157
|
+
function isNativeAddButton(button, zone) {
|
|
158
|
+
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;
|
|
159
|
+
const text = (button.textContent || "").trim();
|
|
160
|
+
return Boolean(text) && new RegExp(`(^|\\s)${String(zone.name).replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`).test(text);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// admin/wireframes.tsx
|
|
164
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
165
|
+
var TEMPLATES = ["generic", "banner", "cards", "imageText", "faq"];
|
|
166
|
+
var DEFAULT_PALETTE = { background: "#F6F6F9", surface: "#DCDCE4", text: "#32324D", accent: "#4945FF" };
|
|
167
|
+
var COLOR = /^#[0-9A-Fa-f]{6}$/;
|
|
168
|
+
var safe = (value, fallback) => value && COLOR.test(value) ? value : fallback;
|
|
169
|
+
var lines = (x, y, w, n, gap = 10) => Array.from({ length: n }, (_, i) => [x, y + i * gap, i === n - 1 ? w * 0.6 : w, 5, "text"]);
|
|
170
|
+
var shapes = {
|
|
171
|
+
generic: [[24, 24, 120, 12, "text"], ...lines(24, 48, 200, 3), [24, 90, 272, 66, "surface", 6]],
|
|
172
|
+
banner: [[0, 0, 320, 180, "surface", 0], [32, 52, 160, 14, "text"], ...lines(32, 80, 150, 2), [32, 116, 70, 20, "accent", 4]],
|
|
173
|
+
cards: [[24, 20, 140, 10, "text"], ...[24, 120, 216].flatMap((x) => [[x, 44, 80, 56, "surface", 6], [x, 108, 64, 6, "text"], [x, 122, 80, 5, "text"], [x, 132, 50, 5, "text"]])],
|
|
174
|
+
imageText: [[24, 32, 120, 116, "surface", 6], [168, 40, 110, 12, "text"], ...lines(168, 64, 128, 4), [168, 116, 60, 18, "accent", 4]],
|
|
175
|
+
faq: [[24, 20, 140, 12, "text"], ...[48, 84, 120].flatMap((y) => [[24, y, 272, 26, "surface", 4], [36, y + 10, 140, 6, "text"], [278, y + 8, 10, 10, "accent", 5]])]
|
|
176
|
+
};
|
|
177
|
+
function Wireframe({ template, palette, className, noPreview }) {
|
|
178
|
+
if (template === "none") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-wireframe": "none", className, style: { width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 12, color: safe(palette?.text, DEFAULT_PALETTE.text), opacity: 0.6, background: safe(palette?.background, DEFAULT_PALETTE.background) }, children: noPreview || "no preview" });
|
|
179
|
+
const colors = {
|
|
180
|
+
background: safe(palette?.background, DEFAULT_PALETTE.background),
|
|
181
|
+
surface: safe(palette?.surface, DEFAULT_PALETTE.surface),
|
|
182
|
+
text: safe(palette?.text, DEFAULT_PALETTE.text),
|
|
183
|
+
accent: safe(palette?.accent, DEFAULT_PALETTE.accent)
|
|
184
|
+
};
|
|
185
|
+
const key = TEMPLATES.includes(template || "") ? template : "generic";
|
|
186
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
187
|
+
"svg",
|
|
188
|
+
{
|
|
189
|
+
viewBox: "0 0 320 180",
|
|
190
|
+
role: "img",
|
|
191
|
+
"aria-hidden": "true",
|
|
192
|
+
focusable: "false",
|
|
193
|
+
className,
|
|
194
|
+
"data-wireframe": key,
|
|
195
|
+
style: { width: "100%", height: "100%", display: "block", background: colors.background },
|
|
196
|
+
children: shapes[key].map(([x, y, w, h, fill, r], i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x, y, width: w, height: h, rx: r ?? 3, fill: colors[fill] }, i))
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// admin/messages.ts
|
|
202
|
+
var import_react_intl = require("react-intl");
|
|
203
|
+
|
|
204
|
+
// admin/translations/en.json
|
|
205
|
+
var en_default = {
|
|
206
|
+
title: "Blockscene",
|
|
207
|
+
settings: "Gallery",
|
|
208
|
+
gallery: "Block gallery",
|
|
209
|
+
add: "Add block",
|
|
210
|
+
search: "Search blocks",
|
|
211
|
+
clear: "Clear search",
|
|
212
|
+
empty: "No blocks found.",
|
|
213
|
+
preview: "Example preview unavailable",
|
|
214
|
+
zone: "Dynamic zone",
|
|
215
|
+
loading: "Loading catalog\u2026",
|
|
216
|
+
failed: "Could not load the catalog. Close and try again.",
|
|
217
|
+
insertFailed: "Could not create this component. Use the native picker and report its schema.",
|
|
218
|
+
example: "Images are examples; appearance depends on your frontend.",
|
|
219
|
+
openAll: "Open all blocks",
|
|
220
|
+
closeAll: "Close all blocks",
|
|
221
|
+
settingsTitle: "Blockscene",
|
|
222
|
+
settingsIntro: "Gallery thumbnails, wireframe palette and editor preferences. Changes apply the next time the gallery opens; no rebuild is needed.",
|
|
223
|
+
palette: "Wireframe palette",
|
|
224
|
+
background: "Background",
|
|
225
|
+
surface: "Surfaces",
|
|
226
|
+
text: "Text",
|
|
227
|
+
accent: "Accent",
|
|
228
|
+
resetPalette: "Restore default colors",
|
|
229
|
+
components: "Components",
|
|
230
|
+
filter: "Filter by name or UID",
|
|
231
|
+
source: "Thumbnail source",
|
|
232
|
+
manual: "Custom image",
|
|
233
|
+
automatic: "Automatic image",
|
|
234
|
+
wireframe: "Wireframe",
|
|
235
|
+
choose: "Choose image",
|
|
236
|
+
replace: "Replace image",
|
|
237
|
+
useAutomatic: "Use automatic image",
|
|
238
|
+
template: "Wireframe template",
|
|
239
|
+
"templates.generic": "Generic",
|
|
240
|
+
"templates.banner": "Banner",
|
|
241
|
+
"templates.cards": "Cards",
|
|
242
|
+
"templates.imageText": "Image and text",
|
|
243
|
+
"templates.faq": "FAQ",
|
|
244
|
+
brokenMedia: "The selected media no longer exists; the next source is used.",
|
|
245
|
+
editor: "Editor preferences",
|
|
246
|
+
enabled: "Editor enhancements enabled",
|
|
247
|
+
enabledHelp: "Off restores the native picker and accordions. This page stays available to turn it back on.",
|
|
248
|
+
showOpenAll: 'Show "Open all blocks"',
|
|
249
|
+
showCloseAll: 'Show "Close all blocks"',
|
|
250
|
+
initialState: "Initial accordion state",
|
|
251
|
+
"states.closed": "All closed",
|
|
252
|
+
"states.open": "All open",
|
|
253
|
+
"states.remember": "Remember the last open/close all action",
|
|
254
|
+
rememberHelp: "Only the explicit open all / close all buttons update the memory, per user and browser. Opening one block does not.",
|
|
255
|
+
previewUrl: "Preview route base URL",
|
|
256
|
+
previewUrlHelp: "Full URL of your frontend page-preview route, e.g. https://site.test/block-preview/page. Leave empty to reuse the origin of Strapi's native Preview (when configured for the content type) with /block-preview/page. The route must implement the bridge (see README).",
|
|
257
|
+
previewMode: "Initial preview mode",
|
|
258
|
+
"modes.form": "Fields",
|
|
259
|
+
"modes.split": "Fields + page",
|
|
260
|
+
"modes.preview": "Visual editor",
|
|
261
|
+
previewModeHelp: "Applies when opening a document; each editor can switch modes and the browser remembers the last choice.",
|
|
262
|
+
previewV4: "The whole-page preview is available in the Strapi 5 distribution only; these options have no effect on Strapi 4.",
|
|
263
|
+
modeForm: "Fields",
|
|
264
|
+
modeSplit: "Fields + page",
|
|
265
|
+
modePreview: "Visual editor",
|
|
266
|
+
previewPane: "Page preview",
|
|
267
|
+
resize: "Resize preview pane",
|
|
268
|
+
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.",
|
|
269
|
+
previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
|
|
270
|
+
previewFailed: "The preview did not answer within 15 s. If the frontend is still loading it will appear by itself; the form stays usable.",
|
|
271
|
+
previewReady: "Page preview \xB7 unsaved changes",
|
|
272
|
+
previewLoading: "Loading preview\u2026",
|
|
273
|
+
retry: "Try again",
|
|
274
|
+
editText: "Edit text",
|
|
275
|
+
editHelp: 'Unsaved changes: "Apply" updates the form and the preview; saving and publishing stay in the panel.',
|
|
276
|
+
editUnsupported: "This field has no editor in this dialog; edit it in the form.",
|
|
277
|
+
apply: "Apply",
|
|
278
|
+
cancel: "Cancel",
|
|
279
|
+
close: "Close",
|
|
280
|
+
blockPreviewInForm: "Show preview above fields in form mode",
|
|
281
|
+
blockPreviewInFormHelp: "In form mode an expanded block shows a compact, collapsible read-only preview of its unsaved values above its fields. Side by side and preview modes never show it; the page preview is where editing happens.",
|
|
282
|
+
zoneFull: "The zone already has its maximum number of blocks.",
|
|
283
|
+
insertMoved: "Could not insert at that position; the zone changed.",
|
|
284
|
+
disabledByServer: "BLOCKSCENE_DISABLED is set on the server. The native editor is forced until the server restarts without it.",
|
|
285
|
+
save: "Save",
|
|
286
|
+
saved: "Settings saved.",
|
|
287
|
+
saveFailed: "Could not save settings.",
|
|
288
|
+
unsaved: "Unsaved changes",
|
|
289
|
+
denied: "Access denied.",
|
|
290
|
+
loadFailed: "Could not load settings. Reload to try again.",
|
|
291
|
+
invalidColor: "Colors must use #RRGGBB.",
|
|
292
|
+
previewLabel: "Palette preview",
|
|
293
|
+
removeGroup: "Remove group",
|
|
294
|
+
diagTitle: "Block groups need attention; publishing is refused until they are fixed:",
|
|
295
|
+
diagCloseBeforeOpen: 'Row {n}: close marker "{uid}" has no open marker before it.',
|
|
296
|
+
diagMismatch: 'Row {n}: close marker "{uid}" does not match the open group "{open}" (expected "{expected}").',
|
|
297
|
+
diagUnclosed: 'Row {n}: group "{uid}" is not closed (expected "{expected}").',
|
|
298
|
+
publishBlocked: "Publishing is refused while block groups are unbalanced.",
|
|
299
|
+
diagSummary: "{count, plural, one {# block group problem} other {# block group problems}}; publishing is refused until fixed",
|
|
300
|
+
diagDetails: "Details",
|
|
301
|
+
diagInsertClose: 'Insert the missing "{expected}" after row {n}',
|
|
302
|
+
diagStrayHint: "Remove the stray marker with the row's own delete action, or move it after an open marker.",
|
|
303
|
+
modeGroup: "Editing mode",
|
|
304
|
+
saveDisabledHint: "No unsaved changes to save.",
|
|
305
|
+
publishDisabledHint: "Publishing is unavailable: save first, fix the errors shown in the form, or check your permissions.",
|
|
306
|
+
countAll: "{count} blocks",
|
|
307
|
+
countFiltered: "{shown} of {total}",
|
|
308
|
+
filterCategory: "Filter by category",
|
|
309
|
+
allCategories: "All categories",
|
|
310
|
+
showFields: "Fields",
|
|
311
|
+
showFieldsHint: "Show the field list on each block",
|
|
312
|
+
columns: "Columns",
|
|
313
|
+
noPreview: "no preview",
|
|
314
|
+
"templates.none": "No preview",
|
|
315
|
+
noChanges: "No unsaved changes"
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
// admin/translations/pt-BR.json
|
|
319
|
+
var pt_BR_default = {
|
|
320
|
+
title: "Blockscene",
|
|
321
|
+
settings: "Galeria",
|
|
322
|
+
gallery: "Galeria de blocos",
|
|
323
|
+
add: "Adicionar bloco",
|
|
324
|
+
search: "Buscar blocos",
|
|
325
|
+
clear: "Limpar busca",
|
|
326
|
+
empty: "Nenhum bloco encontrado.",
|
|
327
|
+
preview: "Exemplo visual indispon\xEDvel",
|
|
328
|
+
zone: "Zona din\xE2mica",
|
|
329
|
+
loading: "Carregando cat\xE1logo\u2026",
|
|
330
|
+
failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
|
|
331
|
+
insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
|
|
332
|
+
example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
|
|
333
|
+
openAll: "Abrir todos os blocos",
|
|
334
|
+
closeAll: "Fechar todos os blocos",
|
|
335
|
+
settingsTitle: "Blockscene",
|
|
336
|
+
settingsIntro: "Miniaturas da galeria, paleta dos wireframes e prefer\xEAncias do editor. As mudan\xE7as valem na pr\xF3xima abertura da galeria; n\xE3o \xE9 preciso rebuild.",
|
|
337
|
+
palette: "Paleta dos wireframes",
|
|
338
|
+
background: "Fundo",
|
|
339
|
+
surface: "Superf\xEDcies",
|
|
340
|
+
text: "Texto",
|
|
341
|
+
accent: "Destaque",
|
|
342
|
+
resetPalette: "Restaurar cores padr\xE3o",
|
|
343
|
+
components: "Componentes",
|
|
344
|
+
filter: "Filtrar por nome ou UID",
|
|
345
|
+
source: "Origem da miniatura",
|
|
346
|
+
manual: "Imagem personalizada",
|
|
347
|
+
automatic: "Imagem autom\xE1tica",
|
|
348
|
+
wireframe: "Wireframe",
|
|
349
|
+
choose: "Escolher imagem",
|
|
350
|
+
replace: "Substituir imagem",
|
|
351
|
+
useAutomatic: "Usar imagem autom\xE1tica",
|
|
352
|
+
template: "Modelo de wireframe",
|
|
353
|
+
"templates.generic": "Gen\xE9rico",
|
|
354
|
+
"templates.banner": "Banner",
|
|
355
|
+
"templates.cards": "Cards",
|
|
356
|
+
"templates.imageText": "Imagem e texto",
|
|
357
|
+
"templates.faq": "FAQ",
|
|
358
|
+
brokenMedia: "A m\xEDdia escolhida n\xE3o existe mais; a pr\xF3xima origem \xE9 usada.",
|
|
359
|
+
editor: "Prefer\xEAncias do editor",
|
|
360
|
+
enabled: "Melhorias do editor ativas",
|
|
361
|
+
enabledHelp: "Desligado restaura o seletor e os accordions nativos. Esta p\xE1gina continua dispon\xEDvel para reativar.",
|
|
362
|
+
showOpenAll: 'Mostrar "Abrir todos os blocos"',
|
|
363
|
+
showCloseAll: 'Mostrar "Fechar todos os blocos"',
|
|
364
|
+
initialState: "Estado inicial dos accordions",
|
|
365
|
+
"states.closed": "Todos fechados",
|
|
366
|
+
"states.open": "Todos abertos",
|
|
367
|
+
"states.remember": "Lembrar a \xFAltima a\xE7\xE3o de abrir/fechar todos",
|
|
368
|
+
rememberHelp: "Somente os bot\xF5es de abrir/fechar todos atualizam a mem\xF3ria, por usu\xE1rio e navegador. Abrir um bloco isolado n\xE3o muda.",
|
|
369
|
+
previewUrl: "URL base da rota de preview",
|
|
370
|
+
previewUrlHelp: "URL completa da rota de preview de p\xE1gina do seu frontend, por exemplo https://site.test/block-preview/page. Vazio reutiliza a origem da Preview nativa do Strapi (quando configurada para o tipo de conte\xFAdo) com /block-preview/page. A rota precisa implementar a bridge (ver README).",
|
|
371
|
+
previewMode: "Modo inicial da preview",
|
|
372
|
+
"modes.form": "Campos",
|
|
373
|
+
"modes.split": "Campos + p\xE1gina",
|
|
374
|
+
"modes.preview": "Editor visual",
|
|
375
|
+
previewModeHelp: "Vale ao abrir um documento; cada editor pode trocar de modo e o navegador lembra a \xFAltima escolha.",
|
|
376
|
+
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.",
|
|
377
|
+
modeForm: "Campos",
|
|
378
|
+
modeSplit: "Campos + p\xE1gina",
|
|
379
|
+
modePreview: "Editor visual",
|
|
380
|
+
previewPane: "Preview da p\xE1gina",
|
|
381
|
+
resize: "Redimensionar painel de preview",
|
|
382
|
+
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.",
|
|
383
|
+
previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
|
|
384
|
+
previewFailed: "A preview n\xE3o respondeu em 15 s. Se o frontend ainda estiver carregando, ela aparece sozinha; o formul\xE1rio continua utiliz\xE1vel.",
|
|
385
|
+
previewReady: "Preview da p\xE1gina \xB7 altera\xE7\xF5es n\xE3o salvas",
|
|
386
|
+
previewLoading: "Carregando preview\u2026",
|
|
387
|
+
retry: "Tentar novamente",
|
|
388
|
+
editText: "Editar texto",
|
|
389
|
+
editHelp: 'Altera\xE7\xF5es n\xE3o salvas: "Aplicar" atualiza o formul\xE1rio e a preview; salvar e publicar continuam no painel.',
|
|
390
|
+
editUnsupported: "Este campo n\xE3o tem editor nesta janela; edite-o no formul\xE1rio.",
|
|
391
|
+
apply: "Aplicar",
|
|
392
|
+
cancel: "Cancelar",
|
|
393
|
+
close: "Fechar",
|
|
394
|
+
blockPreviewInForm: "Mostrar preview acima dos campos no modo formul\xE1rio",
|
|
395
|
+
blockPreviewInFormHelp: "No modo formul\xE1rio, um bloco expandido mostra acima dos campos um preview compacto, colaps\xE1vel e somente leitura dos valores n\xE3o salvos. Lado a lado e Preview nunca o mostram; a edi\xE7\xE3o acontece na preview da p\xE1gina.",
|
|
396
|
+
zoneFull: "A zona j\xE1 tem o n\xFAmero m\xE1ximo de blocos.",
|
|
397
|
+
insertMoved: "N\xE3o foi poss\xEDvel inserir nessa posi\xE7\xE3o; a zona mudou.",
|
|
398
|
+
disabledByServer: "BLOCKSCENE_DISABLED est\xE1 definido no servidor. O editor nativo \xE9 for\xE7ado at\xE9 o servidor reiniciar sem essa vari\xE1vel.",
|
|
399
|
+
save: "Salvar",
|
|
400
|
+
saved: "Configura\xE7\xF5es salvas.",
|
|
401
|
+
saveFailed: "N\xE3o foi poss\xEDvel salvar.",
|
|
402
|
+
unsaved: "Altera\xE7\xF5es n\xE3o salvas",
|
|
403
|
+
denied: "Acesso negado.",
|
|
404
|
+
loadFailed: "N\xE3o foi poss\xEDvel carregar. Recarregue para tentar novamente.",
|
|
405
|
+
invalidColor: "As cores devem usar #RRGGBB.",
|
|
406
|
+
previewLabel: "Pr\xE9via da paleta",
|
|
407
|
+
removeGroup: "Remover grupo",
|
|
408
|
+
diagTitle: "Os grupos de blocos precisam de aten\xE7\xE3o; a publica\xE7\xE3o \xE9 recusada at\xE9 a corre\xE7\xE3o:",
|
|
409
|
+
diagCloseBeforeOpen: 'Linha {n}: o marcador de fechamento "{uid}" n\xE3o tem abertura antes dele.',
|
|
410
|
+
diagMismatch: 'Linha {n}: o marcador de fechamento "{uid}" n\xE3o corresponde ao grupo aberto "{open}" (esperado "{expected}").',
|
|
411
|
+
diagUnclosed: 'Linha {n}: o grupo "{uid}" n\xE3o foi fechado (esperado "{expected}").',
|
|
412
|
+
publishBlocked: "A publica\xE7\xE3o \xE9 recusada enquanto os grupos de blocos estiverem desbalanceados.",
|
|
413
|
+
diagSummary: "{count, plural, one {# problema em grupos de blocos} other {# problemas em grupos de blocos}}; a publica\xE7\xE3o \xE9 recusada at\xE9 a corre\xE7\xE3o",
|
|
414
|
+
diagDetails: "Detalhes",
|
|
415
|
+
diagInsertClose: 'Inserir o fechamento "{expected}" que falta depois da linha {n}',
|
|
416
|
+
diagStrayHint: "Remova o marcador \xF3rf\xE3o pela a\xE7\xE3o de excluir da pr\xF3pria linha, ou mova-o para depois de uma abertura.",
|
|
417
|
+
modeGroup: "Modo de edi\xE7\xE3o",
|
|
418
|
+
saveDisabledHint: "N\xE3o h\xE1 altera\xE7\xF5es para salvar.",
|
|
419
|
+
publishDisabledHint: "Publica\xE7\xE3o indispon\xEDvel: salve antes, corrija os erros do formul\xE1rio ou verifique suas permiss\xF5es.",
|
|
420
|
+
countAll: "{count} blocos",
|
|
421
|
+
countFiltered: "{shown} de {total}",
|
|
422
|
+
filterCategory: "Filtrar por categoria",
|
|
423
|
+
allCategories: "Todas as categorias",
|
|
424
|
+
showFields: "Campos",
|
|
425
|
+
showFieldsHint: "Mostrar a lista de campos em cada bloco",
|
|
426
|
+
columns: "Colunas",
|
|
427
|
+
noPreview: "sem preview",
|
|
428
|
+
"templates.none": "Sem preview",
|
|
429
|
+
noChanges: "Sem altera\xE7\xF5es pendentes"
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
// admin/translations/pt.json
|
|
433
|
+
var pt_default = {
|
|
434
|
+
title: "Blockscene",
|
|
435
|
+
settings: "Galeria",
|
|
436
|
+
gallery: "Galeria de blocos",
|
|
437
|
+
add: "Adicionar bloco",
|
|
438
|
+
search: "Pesquisar blocos",
|
|
439
|
+
clear: "Limpar pesquisa",
|
|
440
|
+
empty: "Nenhum bloco encontrado.",
|
|
441
|
+
preview: "Exemplo visual indispon\xEDvel",
|
|
442
|
+
zone: "Zona din\xE2mica",
|
|
443
|
+
loading: "A carregar cat\xE1logo\u2026",
|
|
444
|
+
failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
|
|
445
|
+
insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
|
|
446
|
+
example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
|
|
447
|
+
openAll: "Abrir todos os blocos",
|
|
448
|
+
closeAll: "Fechar todos os blocos",
|
|
449
|
+
settingsTitle: "Blockscene",
|
|
450
|
+
settingsIntro: "Miniaturas da galeria, paleta dos wireframes e prefer\xEAncias do editor. As mudan\xE7as valem na pr\xF3xima abertura da galeria; n\xE3o \xE9 preciso rebuild.",
|
|
451
|
+
palette: "Paleta dos wireframes",
|
|
452
|
+
background: "Fundo",
|
|
453
|
+
surface: "Superf\xEDcies",
|
|
454
|
+
text: "Texto",
|
|
455
|
+
accent: "Destaque",
|
|
456
|
+
resetPalette: "Restaurar cores padr\xE3o",
|
|
457
|
+
components: "Componentes",
|
|
458
|
+
filter: "Filtrar por nome ou UID",
|
|
459
|
+
source: "Origem da miniatura",
|
|
460
|
+
manual: "Imagem personalizada",
|
|
461
|
+
automatic: "Imagem autom\xE1tica",
|
|
462
|
+
wireframe: "Wireframe",
|
|
463
|
+
choose: "Escolher imagem",
|
|
464
|
+
replace: "Substituir imagem",
|
|
465
|
+
useAutomatic: "Usar imagem autom\xE1tica",
|
|
466
|
+
template: "Modelo de wireframe",
|
|
467
|
+
"templates.generic": "Gen\xE9rico",
|
|
468
|
+
"templates.banner": "Banner",
|
|
469
|
+
"templates.cards": "Cards",
|
|
470
|
+
"templates.imageText": "Imagem e texto",
|
|
471
|
+
"templates.faq": "FAQ",
|
|
472
|
+
brokenMedia: "A m\xEDdia escolhida n\xE3o existe mais; a pr\xF3xima origem \xE9 usada.",
|
|
473
|
+
editor: "Prefer\xEAncias do editor",
|
|
474
|
+
enabled: "Melhorias do editor ativas",
|
|
475
|
+
enabledHelp: "Desligado restaura o seletor e os accordions nativos. Esta p\xE1gina continua dispon\xEDvel para reativar.",
|
|
476
|
+
showOpenAll: 'Mostrar "Abrir todos os blocos"',
|
|
477
|
+
showCloseAll: 'Mostrar "Fechar todos os blocos"',
|
|
478
|
+
initialState: "Estado inicial dos accordions",
|
|
479
|
+
"states.closed": "Todos fechados",
|
|
480
|
+
"states.open": "Todos abertos",
|
|
481
|
+
"states.remember": "Lembrar a \xFAltima a\xE7\xE3o de abrir/fechar todos",
|
|
482
|
+
rememberHelp: "Somente os bot\xF5es de abrir/fechar todos atualizam a mem\xF3ria, por usu\xE1rio e navegador. Abrir um bloco isolado n\xE3o muda.",
|
|
483
|
+
previewUrl: "URL base da rota de pr\xE9-visualiza\xE7\xE3o",
|
|
484
|
+
previewUrlHelp: "URL completa da rota de preview de p\xE1gina do seu frontend, por exemplo https://site.test/block-preview/page. Vazio reutiliza a origem da Preview nativa do Strapi (quando configurada para o tipo de conte\xFAdo) com /block-preview/page. A rota precisa implementar a bridge (ver README).",
|
|
485
|
+
previewMode: "Modo inicial da pr\xE9-visualiza\xE7\xE3o",
|
|
486
|
+
"modes.form": "Campos",
|
|
487
|
+
"modes.split": "Campos + p\xE1gina",
|
|
488
|
+
"modes.preview": "Editor visual",
|
|
489
|
+
previewModeHelp: "Vale ao abrir um documento; cada editor pode trocar de modo e o navegador lembra a \xFAltima escolha.",
|
|
490
|
+
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.",
|
|
491
|
+
modeForm: "Campos",
|
|
492
|
+
modeSplit: "Campos + p\xE1gina",
|
|
493
|
+
modePreview: "Editor visual",
|
|
494
|
+
previewPane: "Pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
|
|
495
|
+
resize: "Redimensionar painel de pr\xE9-visualiza\xE7\xE3o",
|
|
496
|
+
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.",
|
|
497
|
+
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.",
|
|
498
|
+
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.",
|
|
499
|
+
previewReady: "Pr\xE9-visualiza\xE7\xE3o da p\xE1gina \xB7 altera\xE7\xF5es por guardar",
|
|
500
|
+
previewLoading: "A carregar pr\xE9-visualiza\xE7\xE3o\u2026",
|
|
501
|
+
retry: "Tentar novamente",
|
|
502
|
+
editText: "Editar texto",
|
|
503
|
+
editHelp: 'Altera\xE7\xF5es por guardar: "Aplicar" atualiza o formul\xE1rio e a pr\xE9-visualiza\xE7\xE3o; guardar e publicar continuam no painel.',
|
|
504
|
+
editUnsupported: "Este campo n\xE3o tem editor nesta janela; edite-o no formul\xE1rio.",
|
|
505
|
+
apply: "Aplicar",
|
|
506
|
+
cancel: "Cancelar",
|
|
507
|
+
close: "Fechar",
|
|
508
|
+
blockPreviewInForm: "Mostrar pr\xE9-visualiza\xE7\xE3o acima dos campos no modo formul\xE1rio",
|
|
509
|
+
blockPreviewInFormHelp: "No modo formul\xE1rio, um bloco expandido mostra acima dos campos uma pr\xE9-visualiza\xE7\xE3o compacta, colaps\xE1vel e s\xF3 de leitura dos valores por guardar. Lado a lado e Pr\xE9-visualiza\xE7\xE3o nunca a mostram; a edi\xE7\xE3o acontece na pr\xE9-visualiza\xE7\xE3o da p\xE1gina.",
|
|
510
|
+
zoneFull: "A zona j\xE1 tem o n\xFAmero m\xE1ximo de blocos.",
|
|
511
|
+
insertMoved: "N\xE3o foi poss\xEDvel inserir nessa posi\xE7\xE3o; a zona mudou.",
|
|
512
|
+
disabledByServer: "BLOCKSCENE_DISABLED est\xE1 definido no servidor. O editor nativo \xE9 for\xE7ado at\xE9 o servidor reiniciar sem essa vari\xE1vel.",
|
|
513
|
+
save: "Guardar",
|
|
514
|
+
saved: "Defini\xE7\xF5es guardadas.",
|
|
515
|
+
saveFailed: "N\xE3o foi poss\xEDvel guardar.",
|
|
516
|
+
unsaved: "Altera\xE7\xF5es por guardar",
|
|
517
|
+
denied: "Acesso negado.",
|
|
518
|
+
loadFailed: "N\xE3o foi poss\xEDvel carregar. Recarregue para tentar novamente.",
|
|
519
|
+
invalidColor: "As cores devem usar #RRGGBB.",
|
|
520
|
+
previewLabel: "Pr\xE9-visualiza\xE7\xE3o da paleta",
|
|
521
|
+
removeGroup: "Remover grupo",
|
|
522
|
+
diagTitle: "Os grupos de blocos precisam de aten\xE7\xE3o; a publica\xE7\xE3o \xE9 recusada at\xE9 \xE0 corre\xE7\xE3o:",
|
|
523
|
+
diagCloseBeforeOpen: 'Linha {n}: o marcador de fecho "{uid}" n\xE3o tem abertura antes dele.',
|
|
524
|
+
diagMismatch: 'Linha {n}: o marcador de fecho "{uid}" n\xE3o corresponde ao grupo aberto "{open}" (esperado "{expected}").',
|
|
525
|
+
diagUnclosed: 'Linha {n}: o grupo "{uid}" n\xE3o foi fechado (esperado "{expected}").',
|
|
526
|
+
publishBlocked: "A publica\xE7\xE3o \xE9 recusada enquanto os grupos de blocos estiverem desequilibrados.",
|
|
527
|
+
diagSummary: "{count, plural, one {# problema em grupos de blocos} other {# problemas em grupos de blocos}}; a publica\xE7\xE3o \xE9 recusada at\xE9 \xE0 corre\xE7\xE3o",
|
|
528
|
+
diagDetails: "Detalhes",
|
|
529
|
+
diagInsertClose: 'Inserir o fecho "{expected}" em falta depois da linha {n}',
|
|
530
|
+
diagStrayHint: "Remova o marcador \xF3rf\xE3o pela a\xE7\xE3o de eliminar da pr\xF3pria linha, ou mova-o para depois de uma abertura.",
|
|
531
|
+
modeGroup: "Modo de edi\xE7\xE3o",
|
|
532
|
+
saveDisabledHint: "N\xE3o h\xE1 altera\xE7\xF5es por guardar.",
|
|
533
|
+
publishDisabledHint: "Publica\xE7\xE3o indispon\xEDvel: guarde antes, corrija os erros do formul\xE1rio ou verifique as suas permiss\xF5es.",
|
|
534
|
+
countAll: "{count} blocos",
|
|
535
|
+
countFiltered: "{shown} de {total}",
|
|
536
|
+
filterCategory: "Filtrar por categoria",
|
|
537
|
+
allCategories: "Todas as categorias",
|
|
538
|
+
showFields: "Campos",
|
|
539
|
+
showFieldsHint: "Mostrar a lista de campos em cada bloco",
|
|
540
|
+
columns: "Colunas",
|
|
541
|
+
noPreview: "sem pr\xE9-visualiza\xE7\xE3o",
|
|
542
|
+
"templates.none": "Sem pr\xE9-visualiza\xE7\xE3o",
|
|
543
|
+
noChanges: "Sem altera\xE7\xF5es pendentes"
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// admin/translations/fr.json
|
|
547
|
+
var fr_default = {
|
|
548
|
+
title: "Blockscene",
|
|
549
|
+
settings: "Galerie",
|
|
550
|
+
gallery: "Galerie de blocs",
|
|
551
|
+
add: "Ajouter un bloc",
|
|
552
|
+
search: "Rechercher des blocs",
|
|
553
|
+
clear: "Effacer la recherche",
|
|
554
|
+
empty: "Aucun bloc trouv\xE9.",
|
|
555
|
+
preview: "Aper\xE7u d'exemple indisponible",
|
|
556
|
+
zone: "Zone dynamique",
|
|
557
|
+
loading: "Chargement du catalogue\u2026",
|
|
558
|
+
failed: "Impossible de charger le catalogue. Fermez et r\xE9essayez.",
|
|
559
|
+
insertFailed: "Impossible de cr\xE9er ce composant. Utilisez le s\xE9lecteur natif et signalez son sch\xE9ma.",
|
|
560
|
+
example: "Les images sont des exemples ; l'apparence d\xE9pend de votre frontend.",
|
|
561
|
+
openAll: "Ouvrir tous les blocs",
|
|
562
|
+
closeAll: "Fermer tous les blocs",
|
|
563
|
+
settingsTitle: "Blockscene",
|
|
564
|
+
settingsIntro: "Vignettes de la galerie, palette des wireframes et pr\xE9f\xE9rences de l'\xE9diteur. Les changements s'appliquent \xE0 la prochaine ouverture de la galerie ; aucun rebuild n'est n\xE9cessaire.",
|
|
565
|
+
palette: "Palette des wireframes",
|
|
566
|
+
background: "Fond",
|
|
567
|
+
surface: "Surfaces",
|
|
568
|
+
text: "Texte",
|
|
569
|
+
accent: "Accent",
|
|
570
|
+
resetPalette: "R\xE9tablir les couleurs par d\xE9faut",
|
|
571
|
+
components: "Composants",
|
|
572
|
+
filter: "Filtrer par nom ou UID",
|
|
573
|
+
source: "Source de la vignette",
|
|
574
|
+
manual: "Image personnalis\xE9e",
|
|
575
|
+
automatic: "Image automatique",
|
|
576
|
+
wireframe: "Wireframe",
|
|
577
|
+
choose: "Choisir une image",
|
|
578
|
+
replace: "Remplacer l'image",
|
|
579
|
+
useAutomatic: "Utiliser l'image automatique",
|
|
580
|
+
template: "Mod\xE8le de wireframe",
|
|
581
|
+
"templates.generic": "G\xE9n\xE9rique",
|
|
582
|
+
"templates.banner": "Banni\xE8re",
|
|
583
|
+
"templates.cards": "Cartes",
|
|
584
|
+
"templates.imageText": "Image et texte",
|
|
585
|
+
"templates.faq": "FAQ",
|
|
586
|
+
brokenMedia: "Le m\xE9dia choisi n'existe plus ; la source suivante est utilis\xE9e.",
|
|
587
|
+
editor: "Pr\xE9f\xE9rences de l'\xE9diteur",
|
|
588
|
+
enabled: "Am\xE9liorations de l'\xE9diteur activ\xE9es",
|
|
589
|
+
enabledHelp: "D\xE9sactiv\xE9 r\xE9tablit le s\xE9lecteur et les accord\xE9ons natifs. Cette page reste disponible pour les r\xE9activer.",
|
|
590
|
+
showOpenAll: "Afficher \xAB Ouvrir tous les blocs \xBB",
|
|
591
|
+
showCloseAll: "Afficher \xAB Fermer tous les blocs \xBB",
|
|
592
|
+
initialState: "\xC9tat initial des accord\xE9ons",
|
|
593
|
+
"states.closed": "Tous ferm\xE9s",
|
|
594
|
+
"states.open": "Tous ouverts",
|
|
595
|
+
"states.remember": "M\xE9moriser la derni\xE8re action tout ouvrir/fermer",
|
|
596
|
+
rememberHelp: "Seuls les boutons explicites tout ouvrir / tout fermer mettent la m\xE9moire \xE0 jour, par utilisateur et navigateur. Ouvrir un seul bloc ne change rien.",
|
|
597
|
+
previewUrl: "URL de base de la route d'aper\xE7u",
|
|
598
|
+
previewUrlHelp: "URL compl\xE8te de la route d'aper\xE7u de page de votre frontend, par ex. https://site.test/block-preview/page. Laissez vide pour r\xE9utiliser l'origine de l'aper\xE7u natif de Strapi (s'il est configur\xE9 pour le type de contenu) avec /block-preview/page. La route doit impl\xE9menter le pont (voir README).",
|
|
599
|
+
previewMode: "Mode d'aper\xE7u initial",
|
|
600
|
+
"modes.form": "Champs",
|
|
601
|
+
"modes.split": "Champs + page",
|
|
602
|
+
"modes.preview": "\xC9diteur visuel",
|
|
603
|
+
previewModeHelp: "S'applique \xE0 l'ouverture d'un document ; chaque \xE9diteur peut changer de mode et le navigateur retient le dernier choix.",
|
|
604
|
+
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.",
|
|
605
|
+
modeForm: "Champs",
|
|
606
|
+
modeSplit: "Champs + page",
|
|
607
|
+
modePreview: "\xC9diteur visuel",
|
|
608
|
+
previewPane: "Aper\xE7u de la page",
|
|
609
|
+
resize: "Redimensionner le panneau d'aper\xE7u",
|
|
610
|
+
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.",
|
|
611
|
+
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.",
|
|
612
|
+
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.",
|
|
613
|
+
previewReady: "Aper\xE7u de la page \xB7 modifications non enregistr\xE9es",
|
|
614
|
+
previewLoading: "Chargement de l'aper\xE7u\u2026",
|
|
615
|
+
retry: "R\xE9essayer",
|
|
616
|
+
editText: "Modifier le texte",
|
|
617
|
+
editHelp: "Modifications non enregistr\xE9es : \xAB Appliquer \xBB met \xE0 jour le formulaire et l'aper\xE7u ; enregistrer et publier restent dans le panneau.",
|
|
618
|
+
editUnsupported: "Ce champ n'a pas d'\xE9diteur dans cette fen\xEAtre ; modifiez-le dans le formulaire.",
|
|
619
|
+
apply: "Appliquer",
|
|
620
|
+
cancel: "Annuler",
|
|
621
|
+
close: "Fermer",
|
|
622
|
+
blockPreviewInForm: "Afficher l'aper\xE7u au-dessus des champs en mode formulaire",
|
|
623
|
+
blockPreviewInFormHelp: "En mode formulaire, un bloc d\xE9pli\xE9 affiche au-dessus de ses champs un aper\xE7u compact, repliable et en lecture seule de ses valeurs non enregistr\xE9es. Les modes c\xF4te \xE0 c\xF4te et aper\xE7u ne l'affichent jamais ; l'\xE9dition se fait dans l'aper\xE7u de la page.",
|
|
624
|
+
zoneFull: "La zone contient d\xE9j\xE0 son nombre maximal de blocs.",
|
|
625
|
+
insertMoved: "Impossible d'ins\xE9rer \xE0 cette position ; la zone a chang\xE9.",
|
|
626
|
+
disabledByServer: "BLOCKSCENE_DISABLED est d\xE9fini sur le serveur. L'\xE9diteur natif est impos\xE9 jusqu'au red\xE9marrage du serveur sans cette variable.",
|
|
627
|
+
save: "Enregistrer",
|
|
628
|
+
saved: "Param\xE8tres enregistr\xE9s.",
|
|
629
|
+
saveFailed: "Impossible d'enregistrer les param\xE8tres.",
|
|
630
|
+
unsaved: "Modifications non enregistr\xE9es",
|
|
631
|
+
denied: "Acc\xE8s refus\xE9.",
|
|
632
|
+
loadFailed: "Impossible de charger les param\xE8tres. Rechargez pour r\xE9essayer.",
|
|
633
|
+
invalidColor: "Les couleurs doivent utiliser #RRGGBB.",
|
|
634
|
+
previewLabel: "Aper\xE7u de la palette",
|
|
635
|
+
removeGroup: "Supprimer le groupe",
|
|
636
|
+
diagTitle: "Les groupes de blocs demandent une correction ; la publication est refus\xE9e tant qu'ils ne sont pas corrig\xE9s :",
|
|
637
|
+
diagCloseBeforeOpen: "Ligne {n} : le marqueur de fermeture \xAB {uid} \xBB n'a aucun marqueur d'ouverture avant lui.",
|
|
638
|
+
diagMismatch: "Ligne {n} : le marqueur de fermeture \xAB {uid} \xBB ne correspond pas au groupe ouvert \xAB {open} \xBB (attendu \xAB {expected} \xBB).",
|
|
639
|
+
diagUnclosed: "Ligne {n} : le groupe \xAB {uid} \xBB n'est pas ferm\xE9 (attendu \xAB {expected} \xBB).",
|
|
640
|
+
publishBlocked: "La publication est refus\xE9e tant que les groupes de blocs sont d\xE9s\xE9quilibr\xE9s.",
|
|
641
|
+
diagSummary: "{count, plural, one {# probl\xE8me de groupe de blocs} other {# probl\xE8mes de groupes de blocs}} ; la publication est refus\xE9e jusqu'\xE0 correction",
|
|
642
|
+
diagDetails: "D\xE9tails",
|
|
643
|
+
diagInsertClose: "Ins\xE9rer la fermeture \xAB {expected} \xBB manquante apr\xE8s la ligne {n}",
|
|
644
|
+
diagStrayHint: "Supprimez le marqueur orphelin avec l'action de suppression de la ligne, ou d\xE9placez-le apr\xE8s une ouverture.",
|
|
645
|
+
modeGroup: "Mode d'\xE9dition",
|
|
646
|
+
saveDisabledHint: "Aucune modification \xE0 enregistrer.",
|
|
647
|
+
publishDisabledHint: "Publication indisponible : enregistrez d'abord, corrigez les erreurs du formulaire ou v\xE9rifiez vos droits.",
|
|
648
|
+
countAll: "{count} blocs",
|
|
649
|
+
countFiltered: "{shown} sur {total}",
|
|
650
|
+
filterCategory: "Filtrer par cat\xE9gorie",
|
|
651
|
+
allCategories: "Toutes les cat\xE9gories",
|
|
652
|
+
showFields: "Champs",
|
|
653
|
+
showFieldsHint: "Afficher la liste des champs sur chaque bloc",
|
|
654
|
+
columns: "Colonnes",
|
|
655
|
+
noPreview: "pas d\u2019aper\xE7u",
|
|
656
|
+
"templates.none": "Pas d\u2019aper\xE7u",
|
|
657
|
+
noChanges: "Aucune modification en attente"
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
// admin/translations/es.json
|
|
661
|
+
var es_default = {
|
|
662
|
+
title: "Blockscene",
|
|
663
|
+
settings: "Galer\xEDa",
|
|
664
|
+
gallery: "Galer\xEDa de bloques",
|
|
665
|
+
add: "A\xF1adir bloque",
|
|
666
|
+
search: "Buscar bloques",
|
|
667
|
+
clear: "Borrar b\xFAsqueda",
|
|
668
|
+
empty: "No se encontraron bloques.",
|
|
669
|
+
preview: "Vista previa de ejemplo no disponible",
|
|
670
|
+
zone: "Zona din\xE1mica",
|
|
671
|
+
loading: "Cargando cat\xE1logo\u2026",
|
|
672
|
+
failed: "No se pudo cargar el cat\xE1logo. Cierre e int\xE9ntelo de nuevo.",
|
|
673
|
+
insertFailed: "No se pudo crear este componente. Use el selector nativo e informe de su esquema.",
|
|
674
|
+
example: "Las im\xE1genes son ejemplos; la apariencia depende de su frontend.",
|
|
675
|
+
openAll: "Abrir todos los bloques",
|
|
676
|
+
closeAll: "Cerrar todos los bloques",
|
|
677
|
+
settingsTitle: "Blockscene",
|
|
678
|
+
settingsIntro: "Miniaturas de la galer\xEDa, paleta de los wireframes y preferencias del editor. Los cambios se aplican la pr\xF3xima vez que se abra la galer\xEDa; no hace falta rebuild.",
|
|
679
|
+
palette: "Paleta de wireframes",
|
|
680
|
+
background: "Fondo",
|
|
681
|
+
surface: "Superficies",
|
|
682
|
+
text: "Texto",
|
|
683
|
+
accent: "Acento",
|
|
684
|
+
resetPalette: "Restaurar colores predeterminados",
|
|
685
|
+
components: "Componentes",
|
|
686
|
+
filter: "Filtrar por nombre o UID",
|
|
687
|
+
source: "Origen de la miniatura",
|
|
688
|
+
manual: "Imagen personalizada",
|
|
689
|
+
automatic: "Imagen autom\xE1tica",
|
|
690
|
+
wireframe: "Wireframe",
|
|
691
|
+
choose: "Elegir imagen",
|
|
692
|
+
replace: "Reemplazar imagen",
|
|
693
|
+
useAutomatic: "Usar imagen autom\xE1tica",
|
|
694
|
+
template: "Plantilla de wireframe",
|
|
695
|
+
"templates.generic": "Gen\xE9rico",
|
|
696
|
+
"templates.banner": "Banner",
|
|
697
|
+
"templates.cards": "Tarjetas",
|
|
698
|
+
"templates.imageText": "Imagen y texto",
|
|
699
|
+
"templates.faq": "FAQ",
|
|
700
|
+
brokenMedia: "El medio elegido ya no existe; se usa el siguiente origen.",
|
|
701
|
+
editor: "Preferencias del editor",
|
|
702
|
+
enabled: "Mejoras del editor activadas",
|
|
703
|
+
enabledHelp: "Desactivado restaura el selector y los acordeones nativos. Esta p\xE1gina sigue disponible para reactivarlas.",
|
|
704
|
+
showOpenAll: "Mostrar \xABAbrir todos los bloques\xBB",
|
|
705
|
+
showCloseAll: "Mostrar \xABCerrar todos los bloques\xBB",
|
|
706
|
+
initialState: "Estado inicial de los acordeones",
|
|
707
|
+
"states.closed": "Todos cerrados",
|
|
708
|
+
"states.open": "Todos abiertos",
|
|
709
|
+
"states.remember": "Recordar la \xFAltima acci\xF3n de abrir/cerrar todos",
|
|
710
|
+
rememberHelp: "Solo los botones expl\xEDcitos de abrir/cerrar todos actualizan la memoria, por usuario y navegador. Abrir un solo bloque no la cambia.",
|
|
711
|
+
previewUrl: "URL base de la ruta de vista previa",
|
|
712
|
+
previewUrlHelp: "URL completa de la ruta de vista previa de p\xE1gina de su frontend, p. ej. https://site.test/block-preview/page. D\xE9jela vac\xEDa para reutilizar el origen de la Vista previa nativa de Strapi (si est\xE1 configurada para el tipo de contenido) con /block-preview/page. La ruta debe implementar el puente (ver README).",
|
|
713
|
+
previewMode: "Modo inicial de la vista previa",
|
|
714
|
+
"modes.form": "Campos",
|
|
715
|
+
"modes.split": "Campos + p\xE1gina",
|
|
716
|
+
"modes.preview": "Editor visual",
|
|
717
|
+
previewModeHelp: "Se aplica al abrir un documento; cada editor puede cambiar de modo y el navegador recuerda la \xFAltima elecci\xF3n.",
|
|
718
|
+
previewV4: "La vista previa de p\xE1gina completa solo existe en la distribuci\xF3n Strapi 5; estas opciones no tienen efecto en Strapi 4.",
|
|
719
|
+
modeForm: "Campos",
|
|
720
|
+
modeSplit: "Campos + p\xE1gina",
|
|
721
|
+
modePreview: "Editor visual",
|
|
722
|
+
previewPane: "Vista previa de la p\xE1gina",
|
|
723
|
+
resize: "Redimensionar el panel de vista previa",
|
|
724
|
+
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.",
|
|
725
|
+
previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
|
|
726
|
+
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.",
|
|
727
|
+
previewReady: "Vista previa de la p\xE1gina \xB7 cambios sin guardar",
|
|
728
|
+
previewLoading: "Cargando vista previa\u2026",
|
|
729
|
+
retry: "Reintentar",
|
|
730
|
+
editText: "Editar texto",
|
|
731
|
+
editHelp: "Cambios sin guardar: \xABAplicar\xBB actualiza el formulario y la vista previa; guardar y publicar siguen en el panel.",
|
|
732
|
+
editUnsupported: "Este campo no tiene editor en esta ventana; ed\xEDtelo en el formulario.",
|
|
733
|
+
apply: "Aplicar",
|
|
734
|
+
cancel: "Cancelar",
|
|
735
|
+
close: "Cerrar",
|
|
736
|
+
blockPreviewInForm: "Mostrar vista previa sobre los campos en modo formulario",
|
|
737
|
+
blockPreviewInFormHelp: "En modo formulario, un bloque expandido muestra sobre sus campos una vista previa compacta, plegable y de solo lectura de sus valores sin guardar. Los modos lado a lado y vista previa nunca la muestran; la edici\xF3n ocurre en la vista previa de la p\xE1gina.",
|
|
738
|
+
zoneFull: "La zona ya tiene su n\xFAmero m\xE1ximo de bloques.",
|
|
739
|
+
insertMoved: "No se pudo insertar en esa posici\xF3n; la zona cambi\xF3.",
|
|
740
|
+
disabledByServer: "BLOCKSCENE_DISABLED est\xE1 definido en el servidor. Se fuerza el editor nativo hasta que el servidor se reinicie sin esa variable.",
|
|
741
|
+
save: "Guardar",
|
|
742
|
+
saved: "Ajustes guardados.",
|
|
743
|
+
saveFailed: "No se pudieron guardar los ajustes.",
|
|
744
|
+
unsaved: "Cambios sin guardar",
|
|
745
|
+
denied: "Acceso denegado.",
|
|
746
|
+
loadFailed: "No se pudieron cargar los ajustes. Recargue para reintentar.",
|
|
747
|
+
invalidColor: "Los colores deben usar #RRGGBB.",
|
|
748
|
+
previewLabel: "Vista previa de la paleta",
|
|
749
|
+
removeGroup: "Eliminar grupo",
|
|
750
|
+
diagTitle: "Los grupos de bloques necesitan atenci\xF3n; la publicaci\xF3n se rechaza hasta corregirlos:",
|
|
751
|
+
diagCloseBeforeOpen: "Fila {n}: el marcador de cierre \xAB{uid}\xBB no tiene apertura antes.",
|
|
752
|
+
diagMismatch: "Fila {n}: el marcador de cierre \xAB{uid}\xBB no corresponde al grupo abierto \xAB{open}\xBB (se esperaba \xAB{expected}\xBB).",
|
|
753
|
+
diagUnclosed: "Fila {n}: el grupo \xAB{uid}\xBB no est\xE1 cerrado (se esperaba \xAB{expected}\xBB).",
|
|
754
|
+
publishBlocked: "La publicaci\xF3n se rechaza mientras los grupos de bloques est\xE9n desequilibrados.",
|
|
755
|
+
diagSummary: "{count, plural, one {# problema en grupos de bloques} other {# problemas en grupos de bloques}}; la publicaci\xF3n se rechaza hasta corregirlos",
|
|
756
|
+
diagDetails: "Detalles",
|
|
757
|
+
diagInsertClose: "Insertar el cierre \xAB{expected}\xBB que falta despu\xE9s de la fila {n}",
|
|
758
|
+
diagStrayHint: "Elimine el marcador hu\xE9rfano con la acci\xF3n de borrar de la propia fila, o mu\xE9valo despu\xE9s de una apertura.",
|
|
759
|
+
modeGroup: "Modo de edici\xF3n",
|
|
760
|
+
saveDisabledHint: "No hay cambios que guardar.",
|
|
761
|
+
publishDisabledHint: "Publicaci\xF3n no disponible: guarde antes, corrija los errores del formulario o compruebe sus permisos.",
|
|
762
|
+
countAll: "{count} bloques",
|
|
763
|
+
countFiltered: "{shown} de {total}",
|
|
764
|
+
filterCategory: "Filtrar por categor\xEDa",
|
|
765
|
+
allCategories: "Todas las categor\xEDas",
|
|
766
|
+
showFields: "Campos",
|
|
767
|
+
showFieldsHint: "Mostrar la lista de campos en cada bloque",
|
|
768
|
+
columns: "Columnas",
|
|
769
|
+
noPreview: "sin vista previa",
|
|
770
|
+
"templates.none": "Sin vista previa",
|
|
771
|
+
noChanges: "Sin cambios pendientes"
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// admin/translations/de.json
|
|
775
|
+
var de_default = {
|
|
776
|
+
title: "Blockscene",
|
|
777
|
+
settings: "Galerie",
|
|
778
|
+
gallery: "Blockgalerie",
|
|
779
|
+
add: "Block hinzuf\xFCgen",
|
|
780
|
+
search: "Bl\xF6cke suchen",
|
|
781
|
+
clear: "Suche l\xF6schen",
|
|
782
|
+
empty: "Keine Bl\xF6cke gefunden.",
|
|
783
|
+
preview: "Beispielvorschau nicht verf\xFCgbar",
|
|
784
|
+
zone: "Dynamische Zone",
|
|
785
|
+
loading: "Katalog wird geladen\u2026",
|
|
786
|
+
failed: "Der Katalog konnte nicht geladen werden. Schlie\xDFen und erneut versuchen.",
|
|
787
|
+
insertFailed: "Diese Komponente konnte nicht erstellt werden. Verwenden Sie die native Auswahl und melden Sie ihr Schema.",
|
|
788
|
+
example: "Bilder sind Beispiele; das Aussehen h\xE4ngt von Ihrem Frontend ab.",
|
|
789
|
+
openAll: "Alle Bl\xF6cke \xF6ffnen",
|
|
790
|
+
closeAll: "Alle Bl\xF6cke schlie\xDFen",
|
|
791
|
+
settingsTitle: "Blockscene",
|
|
792
|
+
settingsIntro: "Galerie-Vorschaubilder, Wireframe-Palette und Editor-Einstellungen. \xC4nderungen gelten beim n\xE4chsten \xD6ffnen der Galerie; kein Rebuild n\xF6tig.",
|
|
793
|
+
palette: "Wireframe-Palette",
|
|
794
|
+
background: "Hintergrund",
|
|
795
|
+
surface: "Fl\xE4chen",
|
|
796
|
+
text: "Text",
|
|
797
|
+
accent: "Akzent",
|
|
798
|
+
resetPalette: "Standardfarben wiederherstellen",
|
|
799
|
+
components: "Komponenten",
|
|
800
|
+
filter: "Nach Name oder UID filtern",
|
|
801
|
+
source: "Quelle des Vorschaubilds",
|
|
802
|
+
manual: "Eigenes Bild",
|
|
803
|
+
automatic: "Automatisches Bild",
|
|
804
|
+
wireframe: "Wireframe",
|
|
805
|
+
choose: "Bild w\xE4hlen",
|
|
806
|
+
replace: "Bild ersetzen",
|
|
807
|
+
useAutomatic: "Automatisches Bild verwenden",
|
|
808
|
+
template: "Wireframe-Vorlage",
|
|
809
|
+
"templates.generic": "Allgemein",
|
|
810
|
+
"templates.banner": "Banner",
|
|
811
|
+
"templates.cards": "Karten",
|
|
812
|
+
"templates.imageText": "Bild und Text",
|
|
813
|
+
"templates.faq": "FAQ",
|
|
814
|
+
brokenMedia: "Das gew\xE4hlte Medium existiert nicht mehr; die n\xE4chste Quelle wird verwendet.",
|
|
815
|
+
editor: "Editor-Einstellungen",
|
|
816
|
+
enabled: "Editor-Erweiterungen aktiv",
|
|
817
|
+
enabledHelp: "Aus stellt die native Auswahl und die Akkordeons wieder her. Diese Seite bleibt verf\xFCgbar, um sie wieder einzuschalten.",
|
|
818
|
+
showOpenAll: "\u201EAlle Bl\xF6cke \xF6ffnen\u201C anzeigen",
|
|
819
|
+
showCloseAll: "\u201EAlle Bl\xF6cke schlie\xDFen\u201C anzeigen",
|
|
820
|
+
initialState: "Anfangszustand der Akkordeons",
|
|
821
|
+
"states.closed": "Alle geschlossen",
|
|
822
|
+
"states.open": "Alle ge\xF6ffnet",
|
|
823
|
+
"states.remember": "Letzte Aktion \u201Ealle \xF6ffnen/schlie\xDFen\u201C merken",
|
|
824
|
+
rememberHelp: "Nur die expliziten Schaltfl\xE4chen \u201Ealle \xF6ffnen/schlie\xDFen\u201C aktualisieren die Erinnerung, pro Benutzer und Browser. Das \xD6ffnen eines einzelnen Blocks \xE4ndert nichts.",
|
|
825
|
+
previewUrl: "Basis-URL der Vorschauroute",
|
|
826
|
+
previewUrlHelp: "Vollst\xE4ndige URL der Seitenvorschau-Route Ihres Frontends, z. B. https://site.test/block-preview/page. Leer lassen, um den Ursprung der nativen Strapi-Vorschau (wenn f\xFCr den Inhaltstyp konfiguriert) mit /block-preview/page zu verwenden. Die Route muss die Bridge implementieren (siehe README).",
|
|
827
|
+
previewMode: "Anf\xE4nglicher Vorschaumodus",
|
|
828
|
+
"modes.form": "Felder",
|
|
829
|
+
"modes.split": "Felder + Seite",
|
|
830
|
+
"modes.preview": "Visueller Editor",
|
|
831
|
+
previewModeHelp: "Gilt beim \xD6ffnen eines Dokuments; jeder Redakteur kann den Modus wechseln und der Browser merkt sich die letzte Wahl.",
|
|
832
|
+
previewV4: "Die Ganzseiten-Vorschau gibt es nur in der Strapi-5-Distribution; diese Optionen haben unter Strapi 4 keine Wirkung.",
|
|
833
|
+
modeForm: "Felder",
|
|
834
|
+
modeSplit: "Felder + Seite",
|
|
835
|
+
modePreview: "Visueller Editor",
|
|
836
|
+
previewPane: "Seitenvorschau",
|
|
837
|
+
resize: "Vorschaubereich anpassen",
|
|
838
|
+
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.",
|
|
839
|
+
previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
|
|
840
|
+
previewFailed: "Die Vorschau hat innerhalb von 15 s nicht geantwortet. L\xE4dt das Frontend noch, erscheint sie von selbst; das Formular bleibt benutzbar.",
|
|
841
|
+
previewReady: "Seitenvorschau \xB7 ungespeicherte \xC4nderungen",
|
|
842
|
+
previewLoading: "Vorschau wird geladen\u2026",
|
|
843
|
+
retry: "Erneut versuchen",
|
|
844
|
+
editText: "Text bearbeiten",
|
|
845
|
+
editHelp: "Ungespeicherte \xC4nderungen: \u201E\xDCbernehmen\u201C aktualisiert Formular und Vorschau; Speichern und Ver\xF6ffentlichen bleiben im Panel.",
|
|
846
|
+
editUnsupported: "Dieses Feld hat in diesem Dialog keinen Editor; bearbeiten Sie es im Formular.",
|
|
847
|
+
apply: "\xDCbernehmen",
|
|
848
|
+
cancel: "Abbrechen",
|
|
849
|
+
close: "Schlie\xDFen",
|
|
850
|
+
blockPreviewInForm: "Vorschau \xFCber den Feldern im Formularmodus anzeigen",
|
|
851
|
+
blockPreviewInFormHelp: "Im Formularmodus zeigt ein aufgeklappter Block \xFCber seinen Feldern eine kompakte, einklappbare, schreibgesch\xFCtzte Vorschau seiner ungespeicherten Werte. Nebeneinander und Vorschau zeigen sie nie; bearbeitet wird in der Seitenvorschau.",
|
|
852
|
+
zoneFull: "Die Zone hat bereits die maximale Anzahl an Bl\xF6cken.",
|
|
853
|
+
insertMoved: "An dieser Position konnte nicht eingef\xFCgt werden; die Zone hat sich ge\xE4ndert.",
|
|
854
|
+
disabledByServer: "BLOCKSCENE_DISABLED ist auf dem Server gesetzt. Der native Editor wird erzwungen, bis der Server ohne diese Variable neu startet.",
|
|
855
|
+
save: "Speichern",
|
|
856
|
+
saved: "Einstellungen gespeichert.",
|
|
857
|
+
saveFailed: "Einstellungen konnten nicht gespeichert werden.",
|
|
858
|
+
unsaved: "Ungespeicherte \xC4nderungen",
|
|
859
|
+
denied: "Zugriff verweigert.",
|
|
860
|
+
loadFailed: "Einstellungen konnten nicht geladen werden. Neu laden, um es erneut zu versuchen.",
|
|
861
|
+
invalidColor: "Farben m\xFCssen #RRGGBB verwenden.",
|
|
862
|
+
previewLabel: "Palettenvorschau",
|
|
863
|
+
removeGroup: "Gruppe entfernen",
|
|
864
|
+
diagTitle: "Blockgruppen m\xFCssen korrigiert werden; das Ver\xF6ffentlichen wird bis dahin abgelehnt:",
|
|
865
|
+
diagCloseBeforeOpen: "Zeile {n}: Schlie\xDFmarker \u201E{uid}\u201C hat keinen \xD6ffnungsmarker davor.",
|
|
866
|
+
diagMismatch: "Zeile {n}: Schlie\xDFmarker \u201E{uid}\u201C passt nicht zur offenen Gruppe \u201E{open}\u201C (erwartet \u201E{expected}\u201C).",
|
|
867
|
+
diagUnclosed: "Zeile {n}: Gruppe \u201E{uid}\u201C ist nicht geschlossen (erwartet \u201E{expected}\u201C).",
|
|
868
|
+
publishBlocked: "Das Ver\xF6ffentlichen wird abgelehnt, solange Blockgruppen unausgeglichen sind.",
|
|
869
|
+
diagSummary: "{count, plural, one {# Problem in Blockgruppen} other {# Probleme in Blockgruppen}}; Ver\xF6ffentlichen wird bis zur Korrektur abgelehnt",
|
|
870
|
+
diagDetails: "Details",
|
|
871
|
+
diagInsertClose: "Fehlenden Schlie\xDFmarker \u201E{expected}\u201C nach Zeile {n} einf\xFCgen",
|
|
872
|
+
diagStrayHint: "Entfernen Sie den verwaisten Marker \xFCber die L\xF6schaktion der Zeile oder verschieben Sie ihn hinter einen \xD6ffnungsmarker.",
|
|
873
|
+
modeGroup: "Bearbeitungsmodus",
|
|
874
|
+
saveDisabledHint: "Keine ungespeicherten \xC4nderungen.",
|
|
875
|
+
publishDisabledHint: "Ver\xF6ffentlichen nicht m\xF6glich: zuerst speichern, Formularfehler beheben oder Berechtigungen pr\xFCfen.",
|
|
876
|
+
countAll: "{count} Bl\xF6cke",
|
|
877
|
+
countFiltered: "{shown} von {total}",
|
|
878
|
+
filterCategory: "Nach Kategorie filtern",
|
|
879
|
+
allCategories: "Alle Kategorien",
|
|
880
|
+
showFields: "Felder",
|
|
881
|
+
showFieldsHint: "Feldliste auf jedem Block anzeigen",
|
|
882
|
+
columns: "Spalten",
|
|
883
|
+
noPreview: "keine Vorschau",
|
|
884
|
+
"templates.none": "Keine Vorschau",
|
|
885
|
+
noChanges: "Keine ungespeicherten \xC4nderungen"
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
// admin/translations/it.json
|
|
889
|
+
var it_default = {
|
|
890
|
+
title: "Blockscene",
|
|
891
|
+
settings: "Galleria",
|
|
892
|
+
gallery: "Galleria dei blocchi",
|
|
893
|
+
add: "Aggiungi blocco",
|
|
894
|
+
search: "Cerca blocchi",
|
|
895
|
+
clear: "Cancella ricerca",
|
|
896
|
+
empty: "Nessun blocco trovato.",
|
|
897
|
+
preview: "Anteprima di esempio non disponibile",
|
|
898
|
+
zone: "Zona dinamica",
|
|
899
|
+
loading: "Caricamento del catalogo\u2026",
|
|
900
|
+
failed: "Impossibile caricare il catalogo. Chiudi e riprova.",
|
|
901
|
+
insertFailed: "Impossibile creare questo componente. Usa il selettore nativo e segnala il suo schema.",
|
|
902
|
+
example: "Le immagini sono esempi; l'aspetto dipende dal tuo frontend.",
|
|
903
|
+
openAll: "Apri tutti i blocchi",
|
|
904
|
+
closeAll: "Chiudi tutti i blocchi",
|
|
905
|
+
settingsTitle: "Blockscene",
|
|
906
|
+
settingsIntro: "Miniature della galleria, palette dei wireframe e preferenze dell'editor. Le modifiche valgono alla prossima apertura della galleria; non serve alcun rebuild.",
|
|
907
|
+
palette: "Palette dei wireframe",
|
|
908
|
+
background: "Sfondo",
|
|
909
|
+
surface: "Superfici",
|
|
910
|
+
text: "Testo",
|
|
911
|
+
accent: "Accento",
|
|
912
|
+
resetPalette: "Ripristina i colori predefiniti",
|
|
913
|
+
components: "Componenti",
|
|
914
|
+
filter: "Filtra per nome o UID",
|
|
915
|
+
source: "Origine della miniatura",
|
|
916
|
+
manual: "Immagine personalizzata",
|
|
917
|
+
automatic: "Immagine automatica",
|
|
918
|
+
wireframe: "Wireframe",
|
|
919
|
+
choose: "Scegli immagine",
|
|
920
|
+
replace: "Sostituisci immagine",
|
|
921
|
+
useAutomatic: "Usa immagine automatica",
|
|
922
|
+
template: "Modello di wireframe",
|
|
923
|
+
"templates.generic": "Generico",
|
|
924
|
+
"templates.banner": "Banner",
|
|
925
|
+
"templates.cards": "Card",
|
|
926
|
+
"templates.imageText": "Immagine e testo",
|
|
927
|
+
"templates.faq": "FAQ",
|
|
928
|
+
brokenMedia: "Il media scelto non esiste pi\xF9; viene usata l'origine successiva.",
|
|
929
|
+
editor: "Preferenze dell'editor",
|
|
930
|
+
enabled: "Miglioramenti dell'editor attivi",
|
|
931
|
+
enabledHelp: "Disattivato ripristina il selettore e le fisarmoniche native. Questa pagina resta disponibile per riattivarli.",
|
|
932
|
+
showOpenAll: 'Mostra "Apri tutti i blocchi"',
|
|
933
|
+
showCloseAll: 'Mostra "Chiudi tutti i blocchi"',
|
|
934
|
+
initialState: "Stato iniziale delle fisarmoniche",
|
|
935
|
+
"states.closed": "Tutte chiuse",
|
|
936
|
+
"states.open": "Tutte aperte",
|
|
937
|
+
"states.remember": "Ricorda l'ultima azione apri/chiudi tutti",
|
|
938
|
+
rememberHelp: "Solo i pulsanti espliciti apri tutti / chiudi tutti aggiornano la memoria, per utente e browser. Aprire un singolo blocco non la cambia.",
|
|
939
|
+
previewUrl: "URL di base della route di anteprima",
|
|
940
|
+
previewUrlHelp: "URL completo della route di anteprima pagina del tuo frontend, ad es. https://site.test/block-preview/page. Lascia vuoto per riutilizzare l'origine dell'Anteprima nativa di Strapi (se configurata per il tipo di contenuto) con /block-preview/page. La route deve implementare il bridge (vedi README).",
|
|
941
|
+
previewMode: "Modalit\xE0 iniziale dell'anteprima",
|
|
942
|
+
"modes.form": "Campi",
|
|
943
|
+
"modes.split": "Campi + pagina",
|
|
944
|
+
"modes.preview": "Editor visivo",
|
|
945
|
+
previewModeHelp: "Vale all'apertura di un documento; ogni redattore pu\xF2 cambiare modalit\xE0 e il browser ricorda l'ultima scelta.",
|
|
946
|
+
previewV4: "L'anteprima dell'intera pagina esiste solo nella distribuzione Strapi 5; queste opzioni non hanno effetto su Strapi 4.",
|
|
947
|
+
modeForm: "Campi",
|
|
948
|
+
modeSplit: "Campi + pagina",
|
|
949
|
+
modePreview: "Editor visivo",
|
|
950
|
+
previewPane: "Anteprima della pagina",
|
|
951
|
+
resize: "Ridimensiona il pannello di anteprima",
|
|
952
|
+
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.",
|
|
953
|
+
previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
|
|
954
|
+
previewFailed: "L'anteprima non ha risposto entro 15 s. Se il frontend sta ancora caricando, comparir\xE0 da sola; il modulo resta utilizzabile.",
|
|
955
|
+
previewReady: "Anteprima della pagina \xB7 modifiche non salvate",
|
|
956
|
+
previewLoading: "Caricamento dell'anteprima\u2026",
|
|
957
|
+
retry: "Riprova",
|
|
958
|
+
editText: "Modifica testo",
|
|
959
|
+
editHelp: `Modifiche non salvate: "Applica" aggiorna il modulo e l'anteprima; salvare e pubblicare restano nel pannello.`,
|
|
960
|
+
editUnsupported: "Questo campo non ha un editor in questa finestra; modificalo nel modulo.",
|
|
961
|
+
apply: "Applica",
|
|
962
|
+
cancel: "Annulla",
|
|
963
|
+
close: "Chiudi",
|
|
964
|
+
blockPreviewInForm: "Mostra l'anteprima sopra i campi in modalit\xE0 modulo",
|
|
965
|
+
blockPreviewInFormHelp: "In modalit\xE0 modulo un blocco espanso mostra sopra i suoi campi un'anteprima compatta, richiudibile e di sola lettura dei valori non salvati. Affiancati e Anteprima non la mostrano mai; la modifica avviene nell'anteprima della pagina.",
|
|
966
|
+
zoneFull: "La zona ha gi\xE0 il numero massimo di blocchi.",
|
|
967
|
+
insertMoved: "Impossibile inserire in quella posizione; la zona \xE8 cambiata.",
|
|
968
|
+
disabledByServer: "BLOCKSCENE_DISABLED \xE8 impostato sul server. L'editor nativo \xE8 forzato finch\xE9 il server non riparte senza quella variabile.",
|
|
969
|
+
save: "Salva",
|
|
970
|
+
saved: "Impostazioni salvate.",
|
|
971
|
+
saveFailed: "Impossibile salvare le impostazioni.",
|
|
972
|
+
unsaved: "Modifiche non salvate",
|
|
973
|
+
denied: "Accesso negato.",
|
|
974
|
+
loadFailed: "Impossibile caricare le impostazioni. Ricarica per riprovare.",
|
|
975
|
+
invalidColor: "I colori devono usare #RRGGBB.",
|
|
976
|
+
previewLabel: "Anteprima della palette",
|
|
977
|
+
removeGroup: "Rimuovi gruppo",
|
|
978
|
+
diagTitle: "I gruppi di blocchi richiedono attenzione; la pubblicazione \xE8 rifiutata finch\xE9 non vengono corretti:",
|
|
979
|
+
diagCloseBeforeOpen: `Riga {n}: il marcatore di chiusura "{uid}" non ha un'apertura prima.`,
|
|
980
|
+
diagMismatch: 'Riga {n}: il marcatore di chiusura "{uid}" non corrisponde al gruppo aperto "{open}" (atteso "{expected}").',
|
|
981
|
+
diagUnclosed: 'Riga {n}: il gruppo "{uid}" non \xE8 chiuso (atteso "{expected}").',
|
|
982
|
+
publishBlocked: "La pubblicazione \xE8 rifiutata finch\xE9 i gruppi di blocchi sono sbilanciati.",
|
|
983
|
+
diagSummary: "{count, plural, one {# problema nei gruppi di blocchi} other {# problemi nei gruppi di blocchi}}; la pubblicazione \xE8 rifiutata finch\xE9 non vengono corretti",
|
|
984
|
+
diagDetails: "Dettagli",
|
|
985
|
+
diagInsertClose: 'Inserisci la chiusura "{expected}" mancante dopo la riga {n}',
|
|
986
|
+
diagStrayHint: "Rimuovi il marcatore orfano con l'azione di eliminazione della riga, oppure spostalo dopo un'apertura.",
|
|
987
|
+
modeGroup: "Modalit\xE0 di modifica",
|
|
988
|
+
saveDisabledHint: "Nessuna modifica da salvare.",
|
|
989
|
+
publishDisabledHint: "Pubblicazione non disponibile: salva prima, correggi gli errori del modulo o verifica i permessi.",
|
|
990
|
+
countAll: "{count} blocchi",
|
|
991
|
+
countFiltered: "{shown} di {total}",
|
|
992
|
+
filterCategory: "Filtra per categoria",
|
|
993
|
+
allCategories: "Tutte le categorie",
|
|
994
|
+
showFields: "Campi",
|
|
995
|
+
showFieldsHint: "Mostra l\u2019elenco dei campi su ogni blocco",
|
|
996
|
+
columns: "Colonne",
|
|
997
|
+
noPreview: "nessuna anteprima",
|
|
998
|
+
"templates.none": "Nessuna anteprima",
|
|
999
|
+
noChanges: "Nessuna modifica in sospeso"
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
// admin/translations/nl.json
|
|
1003
|
+
var nl_default = {
|
|
1004
|
+
title: "Blockscene",
|
|
1005
|
+
settings: "Galerij",
|
|
1006
|
+
gallery: "Blokkengalerij",
|
|
1007
|
+
add: "Blok toevoegen",
|
|
1008
|
+
search: "Blokken zoeken",
|
|
1009
|
+
clear: "Zoekopdracht wissen",
|
|
1010
|
+
empty: "Geen blokken gevonden.",
|
|
1011
|
+
preview: "Voorbeeldweergave niet beschikbaar",
|
|
1012
|
+
zone: "Dynamische zone",
|
|
1013
|
+
loading: "Catalogus laden\u2026",
|
|
1014
|
+
failed: "De catalogus kon niet worden geladen. Sluit en probeer opnieuw.",
|
|
1015
|
+
insertFailed: "Dit component kon niet worden aangemaakt. Gebruik de native kiezer en meld het schema.",
|
|
1016
|
+
example: "Afbeeldingen zijn voorbeelden; het uiterlijk hangt af van uw frontend.",
|
|
1017
|
+
openAll: "Alle blokken openen",
|
|
1018
|
+
closeAll: "Alle blokken sluiten",
|
|
1019
|
+
settingsTitle: "Blockscene",
|
|
1020
|
+
settingsIntro: "Galerijminiaturen, wireframe-palet en editorvoorkeuren. Wijzigingen gelden bij de volgende opening van de galerij; geen rebuild nodig.",
|
|
1021
|
+
palette: "Wireframe-palet",
|
|
1022
|
+
background: "Achtergrond",
|
|
1023
|
+
surface: "Vlakken",
|
|
1024
|
+
text: "Tekst",
|
|
1025
|
+
accent: "Accent",
|
|
1026
|
+
resetPalette: "Standaardkleuren herstellen",
|
|
1027
|
+
components: "Componenten",
|
|
1028
|
+
filter: "Filteren op naam of UID",
|
|
1029
|
+
source: "Bron van de miniatuur",
|
|
1030
|
+
manual: "Eigen afbeelding",
|
|
1031
|
+
automatic: "Automatische afbeelding",
|
|
1032
|
+
wireframe: "Wireframe",
|
|
1033
|
+
choose: "Afbeelding kiezen",
|
|
1034
|
+
replace: "Afbeelding vervangen",
|
|
1035
|
+
useAutomatic: "Automatische afbeelding gebruiken",
|
|
1036
|
+
template: "Wireframe-sjabloon",
|
|
1037
|
+
"templates.generic": "Algemeen",
|
|
1038
|
+
"templates.banner": "Banner",
|
|
1039
|
+
"templates.cards": "Kaarten",
|
|
1040
|
+
"templates.imageText": "Afbeelding en tekst",
|
|
1041
|
+
"templates.faq": "FAQ",
|
|
1042
|
+
brokenMedia: "Het gekozen medium bestaat niet meer; de volgende bron wordt gebruikt.",
|
|
1043
|
+
editor: "Editorvoorkeuren",
|
|
1044
|
+
enabled: "Editorverbeteringen ingeschakeld",
|
|
1045
|
+
enabledHelp: "Uit herstelt de native kiezer en accordeons. Deze pagina blijft beschikbaar om ze weer in te schakelen.",
|
|
1046
|
+
showOpenAll: '"Alle blokken openen" tonen',
|
|
1047
|
+
showCloseAll: '"Alle blokken sluiten" tonen',
|
|
1048
|
+
initialState: "Beginstand van de accordeons",
|
|
1049
|
+
"states.closed": "Alle gesloten",
|
|
1050
|
+
"states.open": "Alle open",
|
|
1051
|
+
"states.remember": "Laatste actie alles openen/sluiten onthouden",
|
|
1052
|
+
rememberHelp: "Alleen de expliciete knoppen alles openen / alles sluiten werken het geheugen bij, per gebruiker en browser. E\xE9n blok openen verandert niets.",
|
|
1053
|
+
previewUrl: "Basis-URL van de voorbeeldroute",
|
|
1054
|
+
previewUrlHelp: "Volledige URL van de paginavoorbeeldroute van uw frontend, bijv. https://site.test/block-preview/page. Laat leeg om de oorsprong van Strapi's native Preview (indien geconfigureerd voor het contenttype) met /block-preview/page te hergebruiken. De route moet de bridge implementeren (zie README).",
|
|
1055
|
+
previewMode: "Beginmodus van het voorbeeld",
|
|
1056
|
+
"modes.form": "Velden",
|
|
1057
|
+
"modes.split": "Velden + pagina",
|
|
1058
|
+
"modes.preview": "Visuele editor",
|
|
1059
|
+
previewModeHelp: "Geldt bij het openen van een document; elke redacteur kan van modus wisselen en de browser onthoudt de laatste keuze.",
|
|
1060
|
+
previewV4: "Het paginavoorbeeld bestaat alleen in de Strapi 5-distributie; deze opties hebben geen effect op Strapi 4.",
|
|
1061
|
+
modeForm: "Velden",
|
|
1062
|
+
modeSplit: "Velden + pagina",
|
|
1063
|
+
modePreview: "Visuele editor",
|
|
1064
|
+
previewPane: "Paginavoorbeeld",
|
|
1065
|
+
resize: "Voorbeeldpaneel aanpassen",
|
|
1066
|
+
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.",
|
|
1067
|
+
previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
|
|
1068
|
+
previewFailed: "Het voorbeeld antwoordde niet binnen 15 s. Als de frontend nog laadt, verschijnt het vanzelf; het formulier blijft bruikbaar.",
|
|
1069
|
+
previewReady: "Paginavoorbeeld \xB7 niet-opgeslagen wijzigingen",
|
|
1070
|
+
previewLoading: "Voorbeeld laden\u2026",
|
|
1071
|
+
retry: "Opnieuw proberen",
|
|
1072
|
+
editText: "Tekst bewerken",
|
|
1073
|
+
editHelp: 'Niet-opgeslagen wijzigingen: "Toepassen" werkt formulier en voorbeeld bij; opslaan en publiceren blijven in het paneel.',
|
|
1074
|
+
editUnsupported: "Dit veld heeft geen editor in dit venster; bewerk het in het formulier.",
|
|
1075
|
+
apply: "Toepassen",
|
|
1076
|
+
cancel: "Annuleren",
|
|
1077
|
+
close: "Sluiten",
|
|
1078
|
+
blockPreviewInForm: "Voorbeeld boven de velden tonen in formuliermodus",
|
|
1079
|
+
blockPreviewInFormHelp: "In formuliermodus toont een uitgeklapt blok boven zijn velden een compact, inklapbaar, alleen-lezen voorbeeld van zijn niet-opgeslagen waarden. Naast elkaar en Voorbeeld tonen het nooit; bewerken gebeurt in het paginavoorbeeld.",
|
|
1080
|
+
zoneFull: "De zone heeft al het maximale aantal blokken.",
|
|
1081
|
+
insertMoved: "Kon niet op die positie invoegen; de zone is veranderd.",
|
|
1082
|
+
disabledByServer: "BLOCKSCENE_DISABLED is op de server ingesteld. De native editor wordt afgedwongen tot de server zonder die variabele herstart.",
|
|
1083
|
+
save: "Opslaan",
|
|
1084
|
+
saved: "Instellingen opgeslagen.",
|
|
1085
|
+
saveFailed: "Instellingen konden niet worden opgeslagen.",
|
|
1086
|
+
unsaved: "Niet-opgeslagen wijzigingen",
|
|
1087
|
+
denied: "Toegang geweigerd.",
|
|
1088
|
+
loadFailed: "Instellingen konden niet worden geladen. Herlaad om opnieuw te proberen.",
|
|
1089
|
+
invalidColor: "Kleuren moeten #RRGGBB gebruiken.",
|
|
1090
|
+
previewLabel: "Paletvoorbeeld",
|
|
1091
|
+
removeGroup: "Groep verwijderen",
|
|
1092
|
+
diagTitle: "Blokgroepen vragen aandacht; publiceren wordt geweigerd tot ze hersteld zijn:",
|
|
1093
|
+
diagCloseBeforeOpen: 'Rij {n}: sluitmarkering "{uid}" heeft geen openingsmarkering ervoor.',
|
|
1094
|
+
diagMismatch: 'Rij {n}: sluitmarkering "{uid}" past niet bij de open groep "{open}" (verwacht "{expected}").',
|
|
1095
|
+
diagUnclosed: 'Rij {n}: groep "{uid}" is niet gesloten (verwacht "{expected}").',
|
|
1096
|
+
publishBlocked: "Publiceren wordt geweigerd zolang blokgroepen niet in balans zijn.",
|
|
1097
|
+
diagSummary: "{count, plural, one {# probleem in blokgroepen} other {# problemen in blokgroepen}}; publiceren wordt geweigerd tot het hersteld is",
|
|
1098
|
+
diagDetails: "Details",
|
|
1099
|
+
diagInsertClose: 'Ontbrekende sluiting "{expected}" invoegen na rij {n}',
|
|
1100
|
+
diagStrayHint: "Verwijder de losse markering met de verwijderactie van de rij, of verplaats hem achter een opening.",
|
|
1101
|
+
modeGroup: "Bewerkmodus",
|
|
1102
|
+
saveDisabledHint: "Geen niet-opgeslagen wijzigingen.",
|
|
1103
|
+
publishDisabledHint: "Publiceren niet beschikbaar: sla eerst op, herstel de fouten in het formulier of controleer uw rechten.",
|
|
1104
|
+
countAll: "{count} blokken",
|
|
1105
|
+
countFiltered: "{shown} van {total}",
|
|
1106
|
+
filterCategory: "Filteren op categorie",
|
|
1107
|
+
allCategories: "Alle categorie\xEBn",
|
|
1108
|
+
showFields: "Velden",
|
|
1109
|
+
showFieldsHint: "Veldenlijst op elk blok tonen",
|
|
1110
|
+
columns: "Kolommen",
|
|
1111
|
+
noPreview: "geen voorbeeld",
|
|
1112
|
+
"templates.none": "Geen voorbeeld",
|
|
1113
|
+
noChanges: "Geen niet-opgeslagen wijzigingen"
|
|
1114
|
+
};
|
|
1115
|
+
|
|
1116
|
+
// admin/messages.ts
|
|
1117
|
+
var PLUGIN_ID = "blockscene";
|
|
1118
|
+
var TRANSLATIONS = { en: en_default, "pt-BR": pt_BR_default, pt: pt_default, fr: fr_default, es: es_default, de: de_default, it: it_default, nl: nl_default };
|
|
1119
|
+
var prefix = (data) => Object.fromEntries(Object.entries(data).map(([key, value]) => [`${PLUGIN_ID}.${key}`, value]));
|
|
1120
|
+
var registerTrads = async ({ locales }) => locales.map((locale) => ({ locale, data: prefix(TRANSLATIONS[locale] || {}) }));
|
|
1121
|
+
function useMessages() {
|
|
1122
|
+
const { formatMessage, locale } = (0, import_react_intl.useIntl)();
|
|
1123
|
+
const out = { locale, f: (key, values) => formatMessage({ id: `${PLUGIN_ID}.${key}`, defaultMessage: en_default[key] }, values) };
|
|
1124
|
+
for (const [key, defaultMessage] of Object.entries(en_default)) {
|
|
1125
|
+
const value = formatMessage({ id: `${PLUGIN_ID}.${key}`, defaultMessage });
|
|
1126
|
+
const [group, item] = key.split(".");
|
|
1127
|
+
if (item) (out[group] || (out[group] = {}))[item] = value;
|
|
1128
|
+
else out[key] = value;
|
|
1129
|
+
}
|
|
1130
|
+
return out;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
// admin/Gallery.tsx
|
|
1134
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1135
|
+
var Columns = import_styled_components.default.div`
|
|
1136
|
+
column-count: ${({ $columns }) => $columns}; column-gap: 12px;
|
|
1137
|
+
> * { break-inside: avoid; -webkit-column-break-inside: avoid; margin-bottom: 12px; }
|
|
1138
|
+
`;
|
|
1139
|
+
var Tile = import_styled_components.default.button`
|
|
1140
|
+
display: flex; flex-direction: column; gap: 8px; text-align: left; width: 100%;
|
|
1141
|
+
padding: 8px; border: 1px solid ${({ theme }) => theme.colors.neutral200};
|
|
1142
|
+
border-radius: 4px; background: ${({ theme }) => theme.colors.neutral0}; cursor: pointer;
|
|
1143
|
+
&:hover { border-color: ${({ theme }) => theme.colors.primary600}; }
|
|
1144
|
+
&:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
|
|
1145
|
+
`;
|
|
1146
|
+
var Clamp = (0, import_styled_components.default)(import_design_system.Typography)` display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; `;
|
|
1147
|
+
var Slider = import_styled_components.default.input`
|
|
1148
|
+
appearance: none; -webkit-appearance: none; width: 8rem; height: 0.4rem; border-radius: 0.4rem; cursor: pointer;
|
|
1149
|
+
background: ${({ theme, $percent }) => `linear-gradient(to right, ${theme.colors.primary600} ${$percent}%, ${theme.colors.neutral200} ${$percent}%)`};
|
|
1150
|
+
&::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 1.6rem; height: 1.6rem; border-radius: 50%; background: ${({ theme }) => theme.colors.neutral0}; border: 0.2rem solid ${({ theme }) => theme.colors.primary600}; cursor: pointer; }
|
|
1151
|
+
&::-moz-range-thumb { width: 1.6rem; height: 1.6rem; border-radius: 50%; background: ${({ theme }) => theme.colors.neutral0}; border: 0.2rem solid ${({ theme }) => theme.colors.primary600}; cursor: pointer; }
|
|
1152
|
+
&:focus-visible { outline: 0.2rem solid ${({ theme }) => theme.colors.primary600}; outline-offset: 0.2rem; }
|
|
1153
|
+
`;
|
|
1154
|
+
var COLUMNS = { key: "blockscene:columns", min: 1, max: 5, initial: 3 };
|
|
1155
|
+
var SHOW_FIELDS_KEY = "blockscene:show-fields";
|
|
1156
|
+
var readColumns = () => {
|
|
1157
|
+
try {
|
|
1158
|
+
const n = Number(window.localStorage.getItem(COLUMNS.key));
|
|
1159
|
+
return n >= COLUMNS.min && n <= COLUMNS.max ? n : COLUMNS.initial;
|
|
1160
|
+
} catch {
|
|
1161
|
+
return COLUMNS.initial;
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
var readShowFields = () => {
|
|
1165
|
+
try {
|
|
1166
|
+
return window.localStorage.getItem(SHOW_FIELDS_KEY) !== "false";
|
|
1167
|
+
} catch {
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
var remember = (key, value) => {
|
|
1172
|
+
try {
|
|
1173
|
+
window.localStorage.setItem(key, value);
|
|
1174
|
+
} catch {
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
var Frame = import_styled_components.default.div`
|
|
1178
|
+
width: 100%; overflow: hidden; border-radius: 4px; line-height: 0;
|
|
1179
|
+
aspect-ratio: ${({ $fixed }) => $fixed ? "16 / 9" : "auto"};
|
|
1180
|
+
background: ${({ theme }) => theme.colors.neutral100};
|
|
1181
|
+
img { width: 100%; height: auto; display: block; }
|
|
1182
|
+
`;
|
|
1183
|
+
function Thumb({ candidates, template, palette, onResolved, noPreview, eager }) {
|
|
1184
|
+
const key = candidates.join("|");
|
|
1185
|
+
const [state, setState] = React.useState({ key, index: 0 });
|
|
1186
|
+
const index = state.key === key ? state.index : 0;
|
|
1187
|
+
const resolved = React.useRef("");
|
|
1188
|
+
const report = (value) => {
|
|
1189
|
+
const tag = `${key}:${value}`;
|
|
1190
|
+
if (resolved.current !== tag) {
|
|
1191
|
+
resolved.current = tag;
|
|
1192
|
+
onResolved?.(value);
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
React.useEffect(() => {
|
|
1196
|
+
if (index >= candidates.length) report(-1);
|
|
1197
|
+
});
|
|
1198
|
+
if (index >= candidates.length) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Wireframe, { template, palette, noPreview }) });
|
|
1199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1200
|
+
"img",
|
|
1201
|
+
{
|
|
1202
|
+
src: candidates[index],
|
|
1203
|
+
alt: "",
|
|
1204
|
+
loading: eager ? "eager" : "lazy",
|
|
1205
|
+
onLoad: () => report(index),
|
|
1206
|
+
onError: () => setState({ key, index: index + 1 })
|
|
1207
|
+
},
|
|
1208
|
+
candidates[index]
|
|
1209
|
+
) });
|
|
1210
|
+
}
|
|
1211
|
+
function Card({ entry, palette, showFields, onSelect }) {
|
|
1212
|
+
const t = useMessages();
|
|
1213
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Tile, { type: "button", onClick: onSelect, title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
|
|
1214
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview }),
|
|
1215
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
|
|
1216
|
+
entry.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
|
|
1217
|
+
showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral500", style: { fontStyle: "italic" }, "data-testid": "block-fields", children: entry.fields.map((f) => `${f.name} (${f.type})`).join(", ") })
|
|
1218
|
+
] });
|
|
1219
|
+
}
|
|
1220
|
+
function ZoneGallery({ zone, components, add, Modal: Modal2, Toggle, get, controlled }) {
|
|
1221
|
+
const t = useMessages();
|
|
1222
|
+
const [ownOpen, setOwnOpen] = React.useState(false);
|
|
1223
|
+
const open = controlled ? controlled.open : ownOpen;
|
|
1224
|
+
const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
|
|
1225
|
+
const [query, setQuery] = React.useState("");
|
|
1226
|
+
const [category, setCategory] = React.useState("all");
|
|
1227
|
+
const [showFields, setShowFields] = React.useState(readShowFields);
|
|
1228
|
+
const [columns, setColumns] = React.useState(readColumns);
|
|
1229
|
+
const [config, setConfig] = React.useState(null);
|
|
1230
|
+
const [error, setError] = React.useState("");
|
|
1231
|
+
React.useEffect(() => {
|
|
1232
|
+
if (controlled) return;
|
|
1233
|
+
const onClick = (event) => {
|
|
1234
|
+
const button = event.target?.closest?.("button");
|
|
1235
|
+
if (!button || !isNativeAddButton(button, zone)) return;
|
|
1236
|
+
event.preventDefault();
|
|
1237
|
+
event.stopPropagation();
|
|
1238
|
+
setOwnOpen(true);
|
|
1239
|
+
};
|
|
1240
|
+
document.addEventListener("click", onClick, true);
|
|
1241
|
+
return () => document.removeEventListener("click", onClick, true);
|
|
1242
|
+
}, [controlled, zone.name, zone.label]);
|
|
1243
|
+
React.useEffect(() => {
|
|
1244
|
+
if (!open) return;
|
|
1245
|
+
let active = true;
|
|
1246
|
+
setError("");
|
|
1247
|
+
setConfig(null);
|
|
1248
|
+
get("/blockscene/catalog").then(({ data }) => {
|
|
1249
|
+
if (active) setConfig(data);
|
|
1250
|
+
}).catch(() => {
|
|
1251
|
+
if (active) setError(t.failed);
|
|
1252
|
+
});
|
|
1253
|
+
return () => {
|
|
1254
|
+
active = false;
|
|
1255
|
+
};
|
|
1256
|
+
}, [open, get, t.failed]);
|
|
1257
|
+
const entries = config ? entriesFor(zone, components, config, query, category) : [];
|
|
1258
|
+
const categories = config ? categoriesFor(zone, components, config) : [];
|
|
1259
|
+
const total = categories.reduce((sum, [, count]) => sum + count, 0);
|
|
1260
|
+
const filtering = query.trim() !== "" || category !== "all";
|
|
1261
|
+
const reset = () => {
|
|
1262
|
+
setQuery("");
|
|
1263
|
+
setCategory("all");
|
|
1264
|
+
};
|
|
1265
|
+
const select = (uid) => {
|
|
1266
|
+
try {
|
|
1267
|
+
if (controlled ? (controlled.onSelect(uid), true) : add(zone, uid)) {
|
|
1268
|
+
setOpen(false);
|
|
1269
|
+
setQuery("");
|
|
1270
|
+
}
|
|
1271
|
+
} catch {
|
|
1272
|
+
setError(t.insertFailed);
|
|
1273
|
+
}
|
|
1274
|
+
};
|
|
1275
|
+
const changeColumns = (value) => {
|
|
1276
|
+
setColumns(value);
|
|
1277
|
+
remember(COLUMNS.key, String(value));
|
|
1278
|
+
};
|
|
1279
|
+
const changeShowFields = (value) => {
|
|
1280
|
+
setShowFields(value);
|
|
1281
|
+
remember(SHOW_FIELDS_KEY, String(value));
|
|
1282
|
+
};
|
|
1283
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1284
|
+
Modal2,
|
|
1285
|
+
{
|
|
1286
|
+
open,
|
|
1287
|
+
onOpenChange: setOpen,
|
|
1288
|
+
title: t.gallery,
|
|
1289
|
+
trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Button, { variant: "secondary", fullWidth: true, onClick: () => setOpen(true), "data-testid": `open-gallery-${zone.name}`, children: [
|
|
1290
|
+
t.add,
|
|
1291
|
+
": ",
|
|
1292
|
+
zone.name
|
|
1293
|
+
] }),
|
|
1294
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
|
|
1295
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
|
|
1296
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "omega", fontWeight: "bold", textColor: "neutral800", style: { whiteSpace: "nowrap" }, "data-testid": `block-count-${zone.name}`, "aria-live": "polite", children: filtering ? t.f("countFiltered", { shown: entries.length, total }) : t.f("countAll", { count: total }) }),
|
|
1297
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1298
|
+
import_design_system.Searchbar,
|
|
1299
|
+
{
|
|
1300
|
+
name: `block-search-${zone.name}`,
|
|
1301
|
+
value: query,
|
|
1302
|
+
placeholder: t.search,
|
|
1303
|
+
clearLabel: t.clear,
|
|
1304
|
+
onClear: () => setQuery(""),
|
|
1305
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1306
|
+
children: t.search
|
|
1307
|
+
}
|
|
1308
|
+
) }),
|
|
1309
|
+
categories.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Box, { style: { width: "14rem" }, "data-testid": `block-category-${zone.name}`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.SingleSelect, { "aria-label": t.filterCategory, size: "S", value: category, onChange: (value) => setCategory(String(value)), children: [
|
|
1310
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: "all", children: t.allCategories }),
|
|
1311
|
+
categories.map(([name, count]) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.SingleSelectOption, { value: name, children: `${name} (${count})` }, name))
|
|
1312
|
+
] }) }),
|
|
1313
|
+
Toggle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Toggle, { name: `block-fields-${zone.name}`, label: t.showFields, hint: t.showFieldsHint, value: showFields, onChange: changeShowFields }),
|
|
1314
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", children: [
|
|
1315
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
|
|
1316
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1317
|
+
Slider,
|
|
1318
|
+
{
|
|
1319
|
+
type: "range",
|
|
1320
|
+
min: COLUMNS.min,
|
|
1321
|
+
max: COLUMNS.max,
|
|
1322
|
+
step: 1,
|
|
1323
|
+
value: columns,
|
|
1324
|
+
"aria-labelledby": `block-columns-${zone.name}`,
|
|
1325
|
+
$percent: (columns - COLUMNS.min) / (COLUMNS.max - COLUMNS.min) * 100,
|
|
1326
|
+
onChange: (e) => changeColumns(Number(e.target.value))
|
|
1327
|
+
}
|
|
1328
|
+
),
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", children: columns })
|
|
1330
|
+
] })
|
|
1331
|
+
] }),
|
|
1332
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
|
|
1333
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 4, style: { overflowY: "auto", maxHeight: "60vh", padding: "4px" }, children: groupEntries(entries).map(({ category: name, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${name}`, children: `${name} (${items.length})` }),
|
|
1335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { entry, palette: config.palette, showFields, onSelect: () => select(entry.uid) }) }, entry.uid)) })
|
|
1336
|
+
] }, name)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 3, alignItems: "center", children: [
|
|
1337
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Typography, { children: t.empty }),
|
|
1338
|
+
filtering && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
|
|
1339
|
+
] })
|
|
1340
|
+
] })
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
var storage = () => {
|
|
1345
|
+
try {
|
|
1346
|
+
return window.localStorage;
|
|
1347
|
+
} catch {
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
};
|
|
1351
|
+
var memoryBase = () => `${window.location.origin}${window.location.pathname.split("/content-manager")[0]}`;
|
|
1352
|
+
function useInitialAccordions({ zones, editor, docKey, contentType, userId }) {
|
|
1353
|
+
const applied = React.useRef("");
|
|
1354
|
+
const user = React.useRef(userId);
|
|
1355
|
+
user.current = userId;
|
|
1356
|
+
const latest = React.useRef(zones);
|
|
1357
|
+
latest.current = zones;
|
|
1358
|
+
React.useEffect(() => {
|
|
1359
|
+
if (!editor?.enabled || !docKey || applied.current === docKey) return;
|
|
1360
|
+
if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
|
|
1361
|
+
applied.current = docKey;
|
|
1362
|
+
return;
|
|
1363
|
+
}
|
|
1364
|
+
applied.current = docKey;
|
|
1365
|
+
let tries = 0;
|
|
1366
|
+
const cancel = (event) => {
|
|
1367
|
+
if (event.target?.closest?.('button[aria-expanded], [data-testid^="block-accordion-controls-"]')) stop();
|
|
1368
|
+
};
|
|
1369
|
+
const stop = () => {
|
|
1370
|
+
clearInterval(timer);
|
|
1371
|
+
document.removeEventListener("click", cancel, true);
|
|
1372
|
+
};
|
|
1373
|
+
document.addEventListener("click", cancel, true);
|
|
1374
|
+
const timer = setInterval(() => {
|
|
1375
|
+
const pending = latest.current.filter((zone) => zone.count > 0);
|
|
1376
|
+
const ready = pending.length > 0 && pending.every((zone) => {
|
|
1377
|
+
const list = findZoneList(zone.label);
|
|
1378
|
+
return list && toggles(list).length >= zone.count;
|
|
1379
|
+
}) && (editor.initialState !== "remember" || user.current);
|
|
1380
|
+
if (!ready && ++tries < 25) return;
|
|
1381
|
+
stop();
|
|
1382
|
+
for (const zone of pending) {
|
|
1383
|
+
const list = findZoneList(zone.label);
|
|
1384
|
+
if (!list) continue;
|
|
1385
|
+
const key = memoryKey({ base: memoryBase(), userId: user.current, contentType, zone: zone.name });
|
|
1386
|
+
setAll(list, initialState(editor, readMemory(storage(), key)) === "open", import_react_dom.unstable_batchedUpdates);
|
|
1387
|
+
}
|
|
1388
|
+
}, 200);
|
|
1389
|
+
return stop;
|
|
1390
|
+
}, [docKey, editor?.enabled, editor?.initialState, contentType]);
|
|
1391
|
+
}
|
|
1392
|
+
function ZoneControls({ zone, editor, contentType, userId }) {
|
|
1393
|
+
const t = useMessages();
|
|
1394
|
+
if (!zone.count || !(editor.showOpenAll || editor.showCloseAll)) return null;
|
|
1395
|
+
const apply = (open) => {
|
|
1396
|
+
const list = findZoneList(zone.label);
|
|
1397
|
+
if (list) setAll(list, open, import_react_dom.unstable_batchedUpdates);
|
|
1398
|
+
writeMemory(storage(), memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }), open ? "open" : "closed");
|
|
1399
|
+
};
|
|
1400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { gap: 2, wrap: "wrap", "data-testid": `block-accordion-controls-${zone.name}`, children: [
|
|
1401
|
+
editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(true), children: t.openAll }),
|
|
1402
|
+
editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Button, { type: "button", variant: "tertiary", size: "S", onClick: () => apply(false), children: t.closeAll })
|
|
1403
|
+
] });
|
|
1404
|
+
}
|
|
1405
|
+
function Gallery({ zones, editor, docKey, contentType, userId, ...props }) {
|
|
1406
|
+
useInitialAccordions({ zones, editor, docKey, contentType, userId });
|
|
1407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
1408
|
+
!zone.full && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneGallery, { zone, ...props }),
|
|
1409
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ZoneControls, { zone, editor, contentType, userId })
|
|
1410
|
+
] }, zone.name)) });
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// admin/Settings.tsx
|
|
1414
|
+
var React2 = __toESM(require("react"));
|
|
1415
|
+
var import_design_system2 = require("@strapi/design-system");
|
|
1416
|
+
var import_styled_components2 = __toESM(require("styled-components"));
|
|
1417
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
1418
|
+
var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
|
|
1419
|
+
var Grid = import_styled_components2.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
|
|
1420
|
+
var Card2 = import_styled_components2.default.div`
|
|
1421
|
+
display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
|
|
1422
|
+
border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral0};
|
|
1423
|
+
`;
|
|
1424
|
+
var Bar = import_styled_components2.default.div`
|
|
1425
|
+
position: fixed; top: 0; z-index: 4; padding: 12px 32px;
|
|
1426
|
+
background: ${({ theme }) => theme.colors.neutral100}; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};
|
|
1427
|
+
box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
|
|
1428
|
+
`;
|
|
1429
|
+
function useMainRect(anchor) {
|
|
1430
|
+
const [rect, setRect] = React2.useState({ left: 0, width: 0 });
|
|
1431
|
+
React2.useEffect(() => {
|
|
1432
|
+
const read = () => {
|
|
1433
|
+
let host = document.getElementById("main-content");
|
|
1434
|
+
for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
|
|
1435
|
+
const r = (host || document.querySelector("main"))?.getBoundingClientRect();
|
|
1436
|
+
if (r) setRect({ left: Math.round(r.left), width: Math.round(r.width) });
|
|
1437
|
+
};
|
|
1438
|
+
read();
|
|
1439
|
+
window.addEventListener("resize", read);
|
|
1440
|
+
return () => window.removeEventListener("resize", read);
|
|
1441
|
+
});
|
|
1442
|
+
return rect;
|
|
1443
|
+
}
|
|
1444
|
+
var Swatches = import_styled_components2.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
|
|
1445
|
+
var Label = import_styled_components2.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
|
|
1446
|
+
function ColorField({ name, label, value, onChange, disabled }) {
|
|
1447
|
+
const valid = COLOR2.test(value);
|
|
1448
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Label, { children: [
|
|
1449
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
|
|
1450
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, children: [
|
|
1451
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
|
|
1452
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1453
|
+
"input",
|
|
1454
|
+
{
|
|
1455
|
+
name,
|
|
1456
|
+
value,
|
|
1457
|
+
disabled,
|
|
1458
|
+
maxLength: 7,
|
|
1459
|
+
"aria-invalid": !valid,
|
|
1460
|
+
onChange: (e) => onChange(e.target.value.trim()),
|
|
1461
|
+
style: { width: 96, fontFamily: "monospace", padding: "6px 8px", border: `1px solid ${valid ? "#dcdce4" : "#d02b20"}`, borderRadius: 4 }
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
] })
|
|
1465
|
+
] });
|
|
1466
|
+
}
|
|
1467
|
+
var permissions = { read: [{ action: "plugin::blockscene.settings.read", subject: null }], update: [{ action: "plugin::blockscene.settings.update", subject: null }] };
|
|
1468
|
+
function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: MediaPicker2, ToggleField: ToggleField2, SelectField: SelectField2, TextField, previewSupported = false }) {
|
|
1469
|
+
const t = useMessages();
|
|
1470
|
+
const { get, put } = useClient();
|
|
1471
|
+
const { canRead, canUpdate, isLoading } = usePermissions2();
|
|
1472
|
+
const [data, setData] = React2.useState(null);
|
|
1473
|
+
const [catalog, setCatalog] = React2.useState(null);
|
|
1474
|
+
const [settings, setSettings] = React2.useState(null);
|
|
1475
|
+
const [media, setMedia] = React2.useState({});
|
|
1476
|
+
const [sources, setSources] = React2.useState({});
|
|
1477
|
+
const [dirty, setDirty] = React2.useState(false);
|
|
1478
|
+
const [saving, setSaving] = React2.useState(false);
|
|
1479
|
+
const [status, setStatus] = React2.useState("");
|
|
1480
|
+
const [failed, setFailed] = React2.useState(false);
|
|
1481
|
+
const [filter, setFilter] = React2.useState("");
|
|
1482
|
+
const [picking, setPicking] = React2.useState(null);
|
|
1483
|
+
React2.useEffect(() => {
|
|
1484
|
+
if (!canRead || isLoading) return;
|
|
1485
|
+
let active = true;
|
|
1486
|
+
Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
|
|
1487
|
+
if (!active) return;
|
|
1488
|
+
setData(s.data);
|
|
1489
|
+
setSettings(s.data.settings);
|
|
1490
|
+
setMedia(s.data.media || {});
|
|
1491
|
+
setCatalog(c.data);
|
|
1492
|
+
}).catch(() => {
|
|
1493
|
+
if (active) setFailed(true);
|
|
1494
|
+
});
|
|
1495
|
+
return () => {
|
|
1496
|
+
active = false;
|
|
1497
|
+
};
|
|
1498
|
+
}, [get, canRead, isLoading]);
|
|
1499
|
+
const update = (patch) => {
|
|
1500
|
+
setSettings((current) => patch(structuredClone(current)));
|
|
1501
|
+
setDirty(true);
|
|
1502
|
+
setStatus("");
|
|
1503
|
+
};
|
|
1504
|
+
const invalid = settings && (Object.values(settings.palette).some((value) => !COLOR2.test(value)) || settings.editor.previewUrl && !/^https?:\/\/\S+$/.test(settings.editor.previewUrl));
|
|
1505
|
+
const save = async () => {
|
|
1506
|
+
if (!settings || invalid || !canUpdate) return;
|
|
1507
|
+
setSaving(true);
|
|
1508
|
+
setStatus("");
|
|
1509
|
+
try {
|
|
1510
|
+
const { data: saved } = await put("/blockscene/settings", settings);
|
|
1511
|
+
setSettings(saved);
|
|
1512
|
+
setDirty(false);
|
|
1513
|
+
setStatus(t.saved);
|
|
1514
|
+
const refreshed = await get("/blockscene/settings");
|
|
1515
|
+
setMedia(refreshed.data.media || {});
|
|
1516
|
+
} catch {
|
|
1517
|
+
setStatus(t.saveFailed);
|
|
1518
|
+
} finally {
|
|
1519
|
+
setSaving(false);
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
const editor = settings?.editor || {};
|
|
1523
|
+
const components = (data?.components || []).filter((c) => `${c.displayName} ${c.uid}`.toLocaleLowerCase().includes(filter.trim().toLocaleLowerCase()));
|
|
1524
|
+
const sourceOf = (uid, manual) => {
|
|
1525
|
+
const index = sources[uid];
|
|
1526
|
+
if (index === void 0) return "\u2026";
|
|
1527
|
+
if (index === -1) return t.wireframe;
|
|
1528
|
+
return index === 0 && manual ? t.manual : t.automatic;
|
|
1529
|
+
};
|
|
1530
|
+
const ready = !isLoading && canRead && !failed && settings && catalog;
|
|
1531
|
+
const header = React2.useRef(null);
|
|
1532
|
+
const [floating, setFloating] = React2.useState(false);
|
|
1533
|
+
const main = useMainRect(header);
|
|
1534
|
+
React2.useEffect(() => {
|
|
1535
|
+
const el = header.current;
|
|
1536
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
1537
|
+
const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
|
|
1538
|
+
observer.observe(el);
|
|
1539
|
+
return () => observer.disconnect();
|
|
1540
|
+
}, [ready]);
|
|
1541
|
+
const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
|
|
1542
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
|
|
1543
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
|
|
1544
|
+
] });
|
|
1545
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
|
|
1546
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
|
|
1547
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
|
|
1548
|
+
controls("")
|
|
1549
|
+
] }) }),
|
|
1550
|
+
floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
|
|
1551
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
|
|
1552
|
+
controls("-floating")
|
|
1553
|
+
] }) }),
|
|
1554
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { textColor: "neutral600", children: t.settingsIntro }),
|
|
1555
|
+
isLoading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1556
|
+
data.disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
|
|
1557
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
1558
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.palette }),
|
|
1559
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1560
|
+
ColorField,
|
|
1561
|
+
{
|
|
1562
|
+
name: `palette-${key}`,
|
|
1563
|
+
label: t[key],
|
|
1564
|
+
value: settings.palette[key],
|
|
1565
|
+
disabled: !canUpdate || saving,
|
|
1566
|
+
onChange: (value) => update((s) => {
|
|
1567
|
+
s.palette[key] = value;
|
|
1568
|
+
return s;
|
|
1569
|
+
})
|
|
1570
|
+
},
|
|
1571
|
+
key
|
|
1572
|
+
)) }),
|
|
1573
|
+
invalid && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
|
|
1575
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", gap: 1, children: [
|
|
1576
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wireframe, { template, palette: settings.palette }) }),
|
|
1577
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
|
|
1578
|
+
] }, template)) }),
|
|
1579
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
|
|
1580
|
+
s.palette = { ...DEFAULT_PALETTE };
|
|
1581
|
+
return s;
|
|
1582
|
+
}), children: t.resetPalette }) })
|
|
1583
|
+
] }) }),
|
|
1584
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
1585
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.editor }),
|
|
1586
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
1587
|
+
s.editor.enabled = v;
|
|
1588
|
+
return s;
|
|
1589
|
+
}) }),
|
|
1590
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
|
|
1591
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
1592
|
+
s.editor.showOpenAll = v;
|
|
1593
|
+
return s;
|
|
1594
|
+
}) }),
|
|
1595
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
1596
|
+
s.editor.showCloseAll = v;
|
|
1597
|
+
return s;
|
|
1598
|
+
}) }),
|
|
1599
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1600
|
+
SelectField2,
|
|
1601
|
+
{
|
|
1602
|
+
name: "editor-initialState",
|
|
1603
|
+
label: t.initialState,
|
|
1604
|
+
value: editor.initialState,
|
|
1605
|
+
disabled: !canUpdate || saving,
|
|
1606
|
+
options: ["closed", "open", "remember"].map((value) => ({ value, label: t.states[value] })),
|
|
1607
|
+
onChange: (v) => update((s) => {
|
|
1608
|
+
s.editor.initialState = v;
|
|
1609
|
+
return s;
|
|
1610
|
+
})
|
|
1611
|
+
}
|
|
1612
|
+
),
|
|
1613
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
|
|
1614
|
+
previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1615
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1616
|
+
TextField,
|
|
1617
|
+
{
|
|
1618
|
+
name: "editor-previewUrl",
|
|
1619
|
+
label: t.previewUrl,
|
|
1620
|
+
value: editor.previewUrl || "",
|
|
1621
|
+
disabled: !canUpdate || saving,
|
|
1622
|
+
placeholder: "https://site.test/block-preview/page",
|
|
1623
|
+
onChange: (v) => update((s) => {
|
|
1624
|
+
s.editor.previewUrl = v.trim();
|
|
1625
|
+
return s;
|
|
1626
|
+
})
|
|
1627
|
+
}
|
|
1628
|
+
),
|
|
1629
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
|
|
1630
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1631
|
+
SelectField2,
|
|
1632
|
+
{
|
|
1633
|
+
name: "editor-previewMode",
|
|
1634
|
+
label: t.previewMode,
|
|
1635
|
+
value: editor.previewMode || "form",
|
|
1636
|
+
disabled: !canUpdate || saving,
|
|
1637
|
+
options: ["form", "split", "preview"].map((value) => ({ value, label: t.modes[value] })),
|
|
1638
|
+
onChange: (v) => update((s) => {
|
|
1639
|
+
s.editor.previewMode = v;
|
|
1640
|
+
return s;
|
|
1641
|
+
})
|
|
1642
|
+
}
|
|
1643
|
+
),
|
|
1644
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
|
|
1645
|
+
data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1646
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
|
|
1647
|
+
s.editor.blockPreviewInForm = v;
|
|
1648
|
+
return s;
|
|
1649
|
+
}) }),
|
|
1650
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
|
|
1651
|
+
] })
|
|
1652
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
|
|
1653
|
+
] }) }),
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
|
|
1655
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "beta", tag: "h2", children: t.components }),
|
|
1656
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
|
|
1657
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
|
|
1658
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
|
|
1659
|
+
const entry = settings.components[component.uid] || {};
|
|
1660
|
+
const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
|
|
1661
|
+
const candidates = candidatesFor(component.uid, meta, catalog);
|
|
1662
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
|
|
1663
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1664
|
+
Thumb,
|
|
1665
|
+
{
|
|
1666
|
+
candidates,
|
|
1667
|
+
template: entry.template,
|
|
1668
|
+
palette: settings.palette,
|
|
1669
|
+
noPreview: t.noPreview,
|
|
1670
|
+
eager: true,
|
|
1671
|
+
onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
|
|
1672
|
+
}
|
|
1673
|
+
),
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
|
|
1676
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
1677
|
+
component.uid,
|
|
1678
|
+
" \xB7 ",
|
|
1679
|
+
component.category
|
|
1680
|
+
] }),
|
|
1681
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
|
|
1682
|
+
t.source,
|
|
1683
|
+
": ",
|
|
1684
|
+
sourceOf(component.uid, Boolean(meta.manualImage)),
|
|
1685
|
+
meta.manualName ? ` (${meta.manualName})` : ""
|
|
1686
|
+
] }),
|
|
1687
|
+
meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
|
|
1688
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", children: [
|
|
1689
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
|
|
1690
|
+
entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
|
|
1691
|
+
update((s) => {
|
|
1692
|
+
delete s.components[component.uid]?.mediaId;
|
|
1693
|
+
if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
|
|
1694
|
+
return s;
|
|
1695
|
+
});
|
|
1696
|
+
setMedia((m) => {
|
|
1697
|
+
const next = { ...m };
|
|
1698
|
+
delete next[component.uid];
|
|
1699
|
+
return next;
|
|
1700
|
+
});
|
|
1701
|
+
}, children: t.useAutomatic })
|
|
1702
|
+
] }),
|
|
1703
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1704
|
+
SelectField2,
|
|
1705
|
+
{
|
|
1706
|
+
name: `template-${component.uid}`,
|
|
1707
|
+
label: t.template,
|
|
1708
|
+
value: entry.template || "generic",
|
|
1709
|
+
disabled: !canUpdate || saving,
|
|
1710
|
+
options: TEMPLATES.map((value) => ({ value, label: t.templates[value] })),
|
|
1711
|
+
onChange: (v) => update((s) => {
|
|
1712
|
+
s.components[component.uid] = { ...s.components[component.uid], template: v };
|
|
1713
|
+
return s;
|
|
1714
|
+
})
|
|
1715
|
+
}
|
|
1716
|
+
)
|
|
1717
|
+
] })
|
|
1718
|
+
] }, component.uid);
|
|
1719
|
+
}) })
|
|
1720
|
+
] }) }),
|
|
1721
|
+
picking && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
|
|
1722
|
+
const uid = picking;
|
|
1723
|
+
setPicking(null);
|
|
1724
|
+
if (!asset?.id) return;
|
|
1725
|
+
update((s) => {
|
|
1726
|
+
s.components[uid] = { ...s.components[uid], mediaId: asset.id };
|
|
1727
|
+
return s;
|
|
1728
|
+
});
|
|
1729
|
+
setMedia((m) => ({ ...m, [uid]: { manualImage: asset.url, manualName: asset.name } }));
|
|
1730
|
+
} })
|
|
1731
|
+
] })
|
|
1732
|
+
] }) });
|
|
1733
|
+
}
|
|
1734
|
+
function register(app, Component) {
|
|
1735
|
+
app.createSettingSection(
|
|
1736
|
+
{ id: "blockscene", intlLabel: { id: "blockscene.title", defaultMessage: "Blockscene" } },
|
|
1737
|
+
[{
|
|
1738
|
+
id: "blockscene-settings",
|
|
1739
|
+
to: "/settings/blockscene",
|
|
1740
|
+
intlLabel: { id: "blockscene.settings", defaultMessage: "Gallery" },
|
|
1741
|
+
Component: async () => Component,
|
|
1742
|
+
permissions: permissions.read
|
|
1743
|
+
}]
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
// admin/catalog.ts
|
|
1748
|
+
var React3 = __toESM(require("react"));
|
|
1749
|
+
function useCatalog(get) {
|
|
1750
|
+
const [catalog, setCatalog] = React3.useState(null);
|
|
1751
|
+
React3.useEffect(() => {
|
|
1752
|
+
let active = true;
|
|
1753
|
+
get("/blockscene/catalog").then(({ data }) => {
|
|
1754
|
+
if (active) setCatalog(data);
|
|
1755
|
+
}).catch(() => {
|
|
1756
|
+
if (active) setCatalog(null);
|
|
1757
|
+
});
|
|
1758
|
+
return () => {
|
|
1759
|
+
active = false;
|
|
1760
|
+
};
|
|
1761
|
+
}, [get]);
|
|
1762
|
+
return catalog;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// admin/strapi4.tsx
|
|
1766
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1767
|
+
function Modal({ open, onOpenChange, trigger, title, children }) {
|
|
1768
|
+
const id = React4.useId();
|
|
1769
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
|
|
1770
|
+
trigger,
|
|
1771
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, children: [
|
|
1772
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { id, variant: "beta", children: title }) }),
|
|
1773
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.ModalBody, { children })
|
|
1774
|
+
] })
|
|
1775
|
+
] });
|
|
1776
|
+
}
|
|
1777
|
+
function Picker() {
|
|
1778
|
+
const c = (0, import_helper_plugin.useCMEditViewDataManager)();
|
|
1779
|
+
const { get } = (0, import_helper_plugin.useFetchClient)();
|
|
1780
|
+
const catalog = useCatalog(get);
|
|
1781
|
+
const components = c.allLayoutData?.components || {};
|
|
1782
|
+
const schema = c.layout || c.allLayoutData?.contentType;
|
|
1783
|
+
const allowed = (c.isCreatingEntry ? c.createActionAllowedFields : c.updateActionAllowedFields) || [];
|
|
1784
|
+
const zones = editableZones(schema, c.modifiedData, (name) => allowed.includes(name) && schema?.metadatas?.[name]?.edit?.editable !== false, !c.addComponentToDynamicZone).map((zone) => ({ ...zone, label: schema?.metadatas?.[zone.name]?.edit?.label || zone.name }));
|
|
1785
|
+
const add = (zone, uid) => {
|
|
1786
|
+
const close = catalog?.groups?.[uid];
|
|
1787
|
+
if (!canInsert(zone, uid, c.modifiedData, components, close ? 2 : 1) || close && !zone.components.includes(close)) return false;
|
|
1788
|
+
c.addComponentToDynamicZone(zone.name, components[uid], components, Boolean(c.formErrors?.[zone.name]));
|
|
1789
|
+
if (close) c.addComponentToDynamicZone(zone.name, components[close], components, Boolean(c.formErrors?.[zone.name]));
|
|
1790
|
+
return true;
|
|
1791
|
+
};
|
|
1792
|
+
if (!catalog?.editor?.enabled) return null;
|
|
1793
|
+
const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
|
|
1794
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1795
|
+
Gallery,
|
|
1796
|
+
{
|
|
1797
|
+
zones,
|
|
1798
|
+
components,
|
|
1799
|
+
add,
|
|
1800
|
+
Modal,
|
|
1801
|
+
Toggle: ToggleField,
|
|
1802
|
+
get,
|
|
1803
|
+
editor: catalog.editor,
|
|
1804
|
+
docKey,
|
|
1805
|
+
contentType: c.slug,
|
|
1806
|
+
userId: import_helper_plugin.auth.getUserInfo?.()?.id
|
|
1807
|
+
}
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system3.Flex, { gap: 3, children: [
|
|
1811
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Switch, { name, "aria-label": label, selected: Boolean(value), disabled, onChange: () => onChange(!value) }),
|
|
1812
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.Typography, { children: label })
|
|
1813
|
+
] });
|
|
1814
|
+
var SelectField = ({ name, label, value, onChange, disabled, options }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelect, { name, label, value, disabled, onChange: (v) => onChange(String(v)), children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system3.SingleSelectOption, { value: o.value, children: o.label }, o.value)) });
|
|
1815
|
+
function MediaPicker({ onClose, onSelect }) {
|
|
1816
|
+
const { components } = (0, import_helper_plugin.useLibrary)();
|
|
1817
|
+
const Dialog = components?.["media-library"];
|
|
1818
|
+
if (!Dialog) {
|
|
1819
|
+
onClose();
|
|
1820
|
+
return null;
|
|
1821
|
+
}
|
|
1822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Dialog, { onClose, allowedTypes: ["images"], onSelectAssets: (assets) => onSelect(assets?.[0]) });
|
|
1823
|
+
}
|
|
1824
|
+
function usePermissions() {
|
|
1825
|
+
const { allowedActions, isLoading } = (0, import_helper_plugin.useRBAC)(permissions);
|
|
1826
|
+
return { canRead: allowedActions.canRead, canUpdate: allowedActions.canUpdate, isLoading };
|
|
1827
|
+
}
|
|
1828
|
+
var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Settings, { useClient: import_helper_plugin.useFetchClient, usePermissions, MediaPicker, ToggleField, SelectField, previewSupported: false });
|
|
1829
|
+
var strapi4_default = {
|
|
1830
|
+
register(app) {
|
|
1831
|
+
register(app, SettingsPage);
|
|
1832
|
+
app.registerPlugin({ id: "blockscene", name: "Blockscene" });
|
|
1833
|
+
},
|
|
1834
|
+
registerTrads,
|
|
1835
|
+
bootstrap(app) {
|
|
1836
|
+
app.injectContentManagerComponent("editView", "right-links", { name: "blockscene", Component: Picker });
|
|
1837
|
+
}
|
|
1838
|
+
};
|