@aduptive/strapi-blockscene 1.0.0-alpha.6 → 1.0.0-alpha.7

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/dist/admin.cjs CHANGED
@@ -50,7 +50,7 @@ var require_groups = __commonJS({
50
50
  var uidOf = (row) => typeof row?.__component === "string" ? row.__component : "";
51
51
  var isOpener2 = (row, g) => Boolean(g) && Object.prototype.hasOwnProperty.call(g, uidOf(row));
52
52
  var isClose2 = (row, g) => Boolean(g) && Object.values(g).includes(uidOf(row));
53
- var blockKey2 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
53
+ var blockKey3 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
54
54
  function validateGroups3(rows, g) {
55
55
  const errors = [];
56
56
  if (!g || !Array.isArray(rows)) return errors;
@@ -92,8 +92,8 @@ var require_groups = __commonJS({
92
92
  const closed = uidOf(rows[end]) === g[uidOf(row)] && end > i;
93
93
  out.push({
94
94
  type: "group",
95
- key: blockKey2(row),
96
- closeKey: closed ? blockKey2(rows[end]) : null,
95
+ key: blockKey3(row),
96
+ closeKey: closed ? blockKey3(rows[end]) : null,
97
97
  row,
98
98
  index: offset + i,
99
99
  depth,
@@ -102,7 +102,7 @@ var require_groups = __commonJS({
102
102
  i = end + 1;
103
103
  continue;
104
104
  }
105
- out.push({ type: "block", key: blockKey2(row), row, index: offset + i, depth, stray: isClose2(row, g) });
105
+ out.push({ type: "block", key: blockKey3(row), row, index: offset + i, depth, stray: isClose2(row, g) });
106
106
  i++;
107
107
  }
108
108
  return out;
@@ -120,7 +120,7 @@ var require_groups = __commonJS({
120
120
  function moveGroup2(rows, key, direction, g) {
121
121
  if (!g) return null;
122
122
  const ranges = topLevelRanges2(rows, g);
123
- const at = ranges.findIndex(([s]) => blockKey2(rows[s]) === String(key));
123
+ const at = ranges.findIndex(([s]) => blockKey3(rows[s]) === String(key));
124
124
  const to = at + (direction === "up" ? -1 : 1);
125
125
  if (at < 0 || to < 0 || to >= ranges.length) return null;
126
126
  const [a, b] = direction === "up" ? [ranges[to], ranges[at]] : [ranges[at], ranges[to]];
@@ -128,12 +128,12 @@ var require_groups = __commonJS({
128
128
  }
129
129
  function removeGroup2(rows, key, g) {
130
130
  if (!g) return null;
131
- const start = rows.findIndex((row) => blockKey2(row) === String(key));
131
+ const start = rows.findIndex((row) => blockKey3(row) === String(key));
132
132
  if (start < 0 || !isOpener2(rows[start], g)) return null;
133
133
  const [, end] = groupRange3(rows, start, g);
134
134
  return [...rows.slice(0, start), ...rows.slice(end + 1)];
135
135
  }
136
- module2.exports = { safeGroups: safeGroups2, validateGroups: validateGroups3, groupRange: groupRange3, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey2, isOpener: isOpener2, isClose: isClose2 };
136
+ module2.exports = { safeGroups: safeGroups2, validateGroups: validateGroups3, groupRange: groupRange3, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey3, isOpener: isOpener2, isClose: isClose2 };
137
137
  }
138
138
  });
139
139
 
@@ -143,15 +143,15 @@ __export(strapi4_exports, {
143
143
  default: () => strapi4_default
144
144
  });
145
145
  module.exports = __toCommonJS(strapi4_exports);
146
- var React8 = __toESM(require("react"));
147
- var import_design_system5 = require("@strapi/design-system");
146
+ var React10 = __toESM(require("react"));
147
+ var import_design_system6 = require("@strapi/design-system");
148
148
  var import_helper_plugin = require("@strapi/helper-plugin");
149
149
 
150
150
  // admin/Gallery.tsx
151
- var React4 = __toESM(require("react"));
152
- var import_react_dom3 = require("react-dom");
151
+ var React5 = __toESM(require("react"));
152
+ var import_react_dom4 = require("react-dom");
153
153
  var import_design_system2 = require("@strapi/design-system");
154
- var import_styled_components3 = __toESM(require("styled-components"));
154
+ var import_styled_components4 = __toESM(require("styled-components"));
155
155
 
156
156
  // admin/model.mjs
157
157
  var import_fractional_indexing = require("fractional-indexing");
@@ -287,9 +287,9 @@ function groupEntries(entries) {
287
287
  const map = /* @__PURE__ */ new Map();
288
288
  for (const entry of entries)
289
289
  map.set(entry.typology, [...map.get(entry.typology) || [], entry]);
290
- return [...map.entries()].map(([typology, items]) => ({
290
+ return [...map.entries()].map(([typology, items2]) => ({
291
291
  typology,
292
- entries: items
292
+ entries: items2
293
293
  }));
294
294
  }
295
295
  function memoryKey({ base = "", userId, contentType, zone }) {
@@ -339,19 +339,23 @@ function fieldText(fields, owner, name, label, locale, on) {
339
339
  const out = {};
340
340
  const text = localized(entry.label, locale) ?? (on && label === name ? humanize(name) : void 0);
341
341
  if (text !== void 0) out.label = text;
342
- for (const key of ["description", "placeholder"]) {
342
+ for (const key of ["description", "placeholder", "help"]) {
343
343
  const value = localized(entry[key], locale);
344
344
  if (value !== void 0) out[key] = value;
345
345
  }
346
346
  return Object.keys(out).length ? out : null;
347
347
  }
348
348
  var labelsOff = (catalog) => !catalog?.editor?.enabled || !catalog.editor.friendlyLabels && !Object.keys(catalog.fields || {}).length;
349
+ var withHelp = (description, help) => description ? `${description} ${help}` : help;
349
350
  function labelEditLayout4(layout, catalog, locale) {
350
351
  const uid = layout?.contentType?.uid;
351
352
  if (labelsOff(catalog) || !uid || catalog.contentTypes?.[uid]?.enabled === false) return layout;
352
353
  const fix = (owner) => (field) => {
353
354
  const text = field?.metadatas && fieldText(catalog.fields, owner, field.name, field.metadatas.label, locale, catalog.editor.friendlyLabels);
354
- return text ? { ...field, metadatas: { ...field.metadatas, ...text } } : field;
355
+ if (!text) return field;
356
+ const { help, ...rest } = text;
357
+ const metadatas = { ...field.metadatas, ...rest };
358
+ return { ...field, metadatas: help === void 0 ? metadatas : { ...metadatas, description: withHelp(metadatas.description, help) } };
355
359
  };
356
360
  const rows = (target, owner) => Array.isArray(target?.layouts?.edit) ? { ...target, layouts: { ...target.layouts, edit: target.layouts.edit.map((row) => row.map(fix(owner))) } } : target;
357
361
  return {
@@ -458,7 +462,7 @@ function useStageSize(el) {
458
462
  return size;
459
463
  }
460
464
  var frameStyle = (device, stage) => {
461
- const width = DEVICES[device];
465
+ const width = typeof device === "number" ? device : DEVICES[device];
462
466
  if (!width || !stage.width) return { left: 0, width: "100%", height: "100%" };
463
467
  const scale = Math.min(1, stage.width / width);
464
468
  return { left: Math.max(0, (stage.width - width * scale) / 2), width, height: stage.height / scale, transform: `scale(${scale})` };
@@ -484,6 +488,8 @@ function findZoneList(label, root = document) {
484
488
  function toggles(list) {
485
489
  return [...list.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
486
490
  }
491
+ var FOLDED = "data-blockscene-folded";
492
+ var shownToggles = (list) => toggles(list).filter((button) => !button.closest(`li[${FOLDED}]`));
487
493
  function planRows(rects, view, margin = 0) {
488
494
  const now = [], later = [];
489
495
  const gap = (r) => Math.max(view.top - margin - r.bottom, r.top - view.bottom - margin, 0);
@@ -521,7 +527,7 @@ function setAll(list, open, batch = (run) => run()) {
521
527
  });
522
528
  return buttons.length;
523
529
  };
524
- const rows = [...list.querySelectorAll(":scope > li")].filter(differs);
530
+ const rows = [...list.querySelectorAll(":scope > li")].filter((li) => !li.hasAttribute(FOLDED) && differs(li));
525
531
  if (!rows.length) return 0;
526
532
  const root = scroller(list);
527
533
  const view = () => root ? root.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
@@ -577,12 +583,16 @@ function setAll(list, open, batch = (run) => run()) {
577
583
  return changed;
578
584
  }
579
585
  function isNativeAddButton(button, zone) {
580
- if (!button || button.getAttribute("aria-expanded") || button.closest('ol[aria-describedby] > li, [role="dialog"], [data-testid^="open-gallery-"], [data-testid^="block-"], [data-testid^="page-preview"], [data-testid^="bp-"], [data-testid^="zone-"], [data-blockscene-row-actions]')) return false;
586
+ if (!button || button.getAttribute("aria-expanded") || button.closest('ol[aria-describedby] > li, [role="dialog"], [role="menu"], [data-testid^="block-"], [data-testid^="page-preview"], [data-testid^="bp-"], [data-testid^="zone-"], [data-blockscene-row-actions]')) return false;
581
587
  const text = (button.textContent || "").trim();
582
588
  const escape = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
583
589
  const names = [...new Set([zone.name, zone.label].filter(Boolean))].map(escape).join("|");
584
590
  return Boolean(text) && new RegExp(`(^|\\s)(${names})$`).test(text);
585
591
  }
592
+ function accordionToggle(closed, open, { showOpenAll, showCloseAll }) {
593
+ const action = showOpenAll && (closed || !showCloseAll) ? "open" : showCloseAll ? "close" : null;
594
+ return action && { action, disabled: action === "open" ? !closed : !open };
595
+ }
586
596
 
587
597
  // admin/wireframes.tsx
588
598
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -634,7 +644,6 @@ var en_default = {
634
644
  title: "Blockscene",
635
645
  settings: "Gallery",
636
646
  gallery: "Block gallery",
637
- add: "Add block",
638
647
  search: "Search blocks",
639
648
  clear: "Clear search",
640
649
  empty: "No blocks found.",
@@ -644,8 +653,9 @@ var en_default = {
644
653
  failed: "Could not load the catalog. Close and try again.",
645
654
  insertFailed: "Could not create this component. Use the native picker and report its schema.",
646
655
  example: "Images are examples; appearance depends on your frontend.",
647
- openAll: "Open all blocks",
648
- closeAll: "Close all blocks",
656
+ expandAll: "Expand all",
657
+ collapseAll: "Collapse all",
658
+ moreActions: "More actions",
649
659
  settingsTitle: "Blockscene",
650
660
  settingsIntro: "Gallery thumbnails, wireframe palette and editor preferences. Changes apply the next time the gallery opens; no rebuild is needed.",
651
661
  palette: "Wireframe palette",
@@ -673,8 +683,9 @@ var en_default = {
673
683
  editor: "Editor preferences",
674
684
  enabled: "Blockscene enabled",
675
685
  enabledHelp: "Off turns the whole plugin off at once, with no restart: every edit view is native again and the layout group publish check stops. Use it if something goes wrong in production.",
676
- showOpenAll: 'Show "Open all blocks"',
677
- showCloseAll: 'Show "Close all blocks"',
686
+ showOpenAll: 'Show "Expand all"',
687
+ showCloseAll: 'Show "Collapse all"',
688
+ toggleHelp: "The zone bar shows one button: with both on it expands while any block is collapsed and collapses them all otherwise; with only one on, it offers that action alone.",
678
689
  showRowThumbnails: "Show block thumbnails in the rows",
679
690
  initialState: "Initial accordion state",
680
691
  "states.closed": "All closed",
@@ -683,6 +694,7 @@ var en_default = {
683
694
  rememberHelp: "Only the explicit open all / close all buttons update the memory, per user and browser. Opening one block does not.",
684
695
  previewUrl: "Preview route base URL",
685
696
  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).",
697
+ previewUrlEmpty: "No preview URL is set: editors get the Fields + page and Visual editor modes only on content types where Strapi's native Preview is configured. Elsewhere the mode menu is not shown.",
686
698
  previewMode: "Initial preview mode",
687
699
  "modes.form": "Fields",
688
700
  "modes.split": "Fields + page",
@@ -701,8 +713,6 @@ var en_default = {
701
713
  resize: "Resize preview pane",
702
714
  resizeHint: "Drag to resize; double-click to reset to half",
703
715
  scrollToHovered: "Scroll to the highlighted block",
704
- 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.",
705
- previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
706
716
  previewFailed: "The preview did not answer within 15 s. If the frontend is still loading it will appear by itself; the form stays usable.",
707
717
  previewLoading: "Loading preview\u2026",
708
718
  retry: "Try again",
@@ -847,8 +857,13 @@ var en_default = {
847
857
  confirmDelete: "Delete block {name}?",
848
858
  confirmDeleteMarker: "This is a group marker: only the marker is removed, not the blocks inside the group, and the group stays unbalanced until it is fixed.",
849
859
  delete: "Delete",
850
- selectMode: "Select blocks to copy",
851
- copySelected: "Copy selected ({count})",
860
+ selectBlocks: "Select blocks",
861
+ selectAll: "Select all",
862
+ selectNone: "Select none",
863
+ selectedCount: "{count} selected",
864
+ copy: "Copy",
865
+ copyNothing: "Select at least one block to copy.",
866
+ selectDone: "Done",
852
867
  paste: "Paste {count, plural, one {# block} other {# blocks}}",
853
868
  pasted: "{count, plural, one {# block pasted} other {# blocks pasted}}.",
854
869
  copied: "{count, plural, one {# block copied} other {# blocks copied}}. Paste on any page of this site.",
@@ -911,7 +926,120 @@ var en_default = {
911
926
  historyMax: "Snapshots per document (maximum)",
912
927
  historyEventDays: "Keep the activity (days)",
913
928
  historyRetentionHelp: "A nightly job empties snapshots older than this or beyond the per-document maximum (the newest are kept) and deletes activity older than its limit. It never deletes media files.",
914
- historyInvalid: "Whole numbers: 1 to 3650 days (the activity kept at least as long as the snapshots) and 1 to 1000 snapshots."
929
+ historyInvalid: "Whole numbers: 1 to 3650 days (the activity kept at least as long as the snapshots) and 1 to 1000 snapshots.",
930
+ fieldHelp: "More information",
931
+ paneTitle: "Page preview toolbar",
932
+ paneHelp: "Checked controls show on the page preview toolbar, in this order. Status and Save/Publish stay together on the right; unchecked controls are hidden.",
933
+ "toolbar.modes": "Editing mode",
934
+ "toolbar.history": "Undo and redo",
935
+ "toolbar.devices": "Page width menu",
936
+ "toolbar.status": "Document status",
937
+ "toolbar.actions": "Save and Publish",
938
+ paneDevices: "Page widths",
939
+ paneDevicesHelp: "Entries of the page width menu, in order; the first one is used until an editor picks another. Custom widths: 240 to 3840 px.",
940
+ paneAddWidth: "Add a width",
941
+ paneWidthLabel: "Label",
942
+ paneWidth: "Width (px)",
943
+ paneRemoveWidth: "Remove width",
944
+ paneInvalid: "Keep 1 to 8 widths, none twice; a custom width needs a label (up to 24 characters, no < or >) and a whole number from 240 to 3840.",
945
+ paneTypeOverride: "Own page preview toolbar for {name}",
946
+ add: "Add block",
947
+ openAll: "Open all blocks",
948
+ closeAll: "Close all blocks",
949
+ 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.",
950
+ previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
951
+ selectMode: "Select blocks to copy",
952
+ copySelected: "Copy selected ({count})",
953
+ trashDays: "Keep deleted documents (days)",
954
+ trashDaysHelp: "Deleted documents stay in the trash that many days (fixed when each one is deleted), then the nightly job deletes them.",
955
+ "historyActions.purge": "Deleted forever",
956
+ contentMenu: "Activity and trash",
957
+ contentTitle: "Content activity and trash",
958
+ contentSubtitle: "Changes made through Strapi (admin, API, plugins) to the content types the version history covers.",
959
+ contentOff: "Version history is off: nothing new is recorded or trashed. Turn it on in Settings, Blockscene.",
960
+ contentLoading: "Loading\u2026",
961
+ contentNone: "\u2014",
962
+ contentUntitled: "(untitled)",
963
+ contentGone: "no longer exists",
964
+ contentOpen: "Open",
965
+ contentPrevious: "Previous",
966
+ contentNext: "Next",
967
+ contentPage: "Page {page} of {pages}, {total} in total",
968
+ contentClear: "Clear filters",
969
+ activityTab: "Activity",
970
+ activityPerson: "Person",
971
+ activityAnyone: "Anyone",
972
+ activityType: "Content type",
973
+ activityAnyType: "All content types",
974
+ activityAction: "Action",
975
+ activityAnyAction: "All actions",
976
+ activityFrom: "From",
977
+ activityTo: "To",
978
+ activitySearch: "Title contains",
979
+ activitySearchButton: "Search",
980
+ activityWhen: "When",
981
+ activityDocument: "Document",
982
+ activityWho: "Who",
983
+ activityWhat: "What",
984
+ activityEmpty: "No activity matches these filters.",
985
+ activityFailed: "The activity could not be loaded.",
986
+ activityRestoredFrom: "Back from the trash",
987
+ trashTab: "Trash",
988
+ trashShowRestored: "Show restored entries",
989
+ trashLocales: "Locales",
990
+ trashDeletedBy: "Deleted by",
991
+ trashDeletedAt: "Deleted",
992
+ trashExpires: "Deleted forever",
993
+ trashExpiresIn: "in {days} days",
994
+ trashExpiresToday: "tonight",
995
+ trashRestoredAs: "Restored",
996
+ trashEmpty: "The trash is empty.",
997
+ trashFailed: "The trash could not be loaded.",
998
+ trashPreview: "Preview",
999
+ trashRestore: "Restore",
1000
+ trashDelete: "Delete forever",
1001
+ trashDeleteTitle: "Delete forever",
1002
+ trashDeleteConfirm: "Delete \u201C{title}\u201D from the trash forever? It cannot be restored afterwards. Media files are not deleted.",
1003
+ trashDeleted: "Deleted forever.",
1004
+ trashDeleteFailed: "It could not be deleted.",
1005
+ trashDraft: "draft",
1006
+ trashPublished: "published",
1007
+ trashFields: "Fields",
1008
+ trashBlocks: "Blocks",
1009
+ trashItems: "{count} item(s)",
1010
+ trashIncoming: "{count} link(s) from other documents or blocks were kept.",
1011
+ trashClose: "Close",
1012
+ restoreTitle: "Restore \u201C{title}\u201D",
1013
+ restoreChecking: "Checking what a restore would do\u2026",
1014
+ restoreIntro: "The document comes back as a draft, with its draft content: check it, then publish it again.",
1015
+ restoreNew: "A new document is created (Strapi does not reuse the original id).",
1016
+ restoreInto: "The locales are added back to the existing document.",
1017
+ restoreLocales: "Locales restored: {locales}",
1018
+ restoreBlocked: "It cannot be restored as it is (nothing is written):",
1019
+ restoreWarnings: "It is restored with these differences:",
1020
+ restoreConfirm: "Restore as draft",
1021
+ restoreCancel: "Cancel",
1022
+ restoreDone: "Restored as a draft.",
1023
+ restoreAlready: "This entry was already restored.",
1024
+ restoreFailed: "The restore failed: nothing was written.",
1025
+ restoreOpen: "Open the restored document",
1026
+ "report.typeGone": "The content type no longer exists.",
1027
+ "report.localeExists": "The document has the {locale} locale again.",
1028
+ "report.unique": "\u201C{value}\u201D is already used in {field} ({locale}) by another document.",
1029
+ "report.singleExists": "This single type has a document again.",
1030
+ "report.nothing": "Nothing left to restore: none of its locales is configured any more.",
1031
+ "report.restored": "Already restored.",
1032
+ "report.published": "A published version existed ({locales}): it is kept in the trash entry, the draft is what comes back.",
1033
+ "report.localeRemoved": "The {locale} locale is no longer configured: skipped.",
1034
+ "report.required": "Required fields are empty ({locale}): {fields}. Fill them before publishing.",
1035
+ "report.fieldsRemoved": "Fields the schema no longer has, left out ({locale}): {fields}.",
1036
+ "report.media": "{count} media file(s) no longer exist, left empty ({locale}).",
1037
+ "report.relations": "{count} related document(s) no longer exist, left out ({locale}).",
1038
+ "report.blocks": "{count} block(s) whose component the zone no longer allows, left out ({locale}).",
1039
+ "report.incoming": "Links from other documents and blocks: {reconnect} put back, {gone} whose owner is gone, {replaced} whose owner points elsewhere now, {published} from published versions (they come back when those documents are published again).",
1040
+ groupCollapse: "Collapse group {label}",
1041
+ groupExpand: "Expand group {label}",
1042
+ groupBlocks: "{count, plural, one {# block} other {# blocks}}"
915
1043
  };
916
1044
 
917
1045
  // admin/translations/pt-BR.json
@@ -919,7 +1047,6 @@ var pt_BR_default = {
919
1047
  title: "Blockscene",
920
1048
  settings: "Galeria",
921
1049
  gallery: "Galeria de blocos",
922
- add: "Adicionar bloco",
923
1050
  search: "Buscar blocos",
924
1051
  clear: "Limpar busca",
925
1052
  empty: "Nenhum bloco encontrado.",
@@ -929,8 +1056,9 @@ var pt_BR_default = {
929
1056
  failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
930
1057
  insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
931
1058
  example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
932
- openAll: "Abrir todos os blocos",
933
- closeAll: "Fechar todos os blocos",
1059
+ expandAll: "Expandir tudo",
1060
+ collapseAll: "Recolher tudo",
1061
+ moreActions: "Mais a\xE7\xF5es",
934
1062
  settingsTitle: "Blockscene",
935
1063
  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.",
936
1064
  palette: "Paleta dos wireframes",
@@ -958,8 +1086,9 @@ var pt_BR_default = {
958
1086
  editor: "Prefer\xEAncias do editor",
959
1087
  enabled: "Blockscene ligado",
960
1088
  enabledHelp: "Desligado, o plugin inteiro para na hora, sem restart: toda tela de edi\xE7\xE3o volta a ser nativa e a verifica\xE7\xE3o de grupos na publica\xE7\xE3o para. Use se algo der errado em produ\xE7\xE3o.",
961
- showOpenAll: 'Mostrar "Abrir todos os blocos"',
962
- showCloseAll: 'Mostrar "Fechar todos os blocos"',
1089
+ showOpenAll: 'Mostrar "Expandir tudo"',
1090
+ showCloseAll: 'Mostrar "Recolher tudo"',
1091
+ toggleHelp: "A barra da zona mostra um \xFAnico bot\xE3o: com as duas op\xE7\xF5es ligadas, ele expande enquanto houver algum bloco recolhido e, sen\xE3o, recolhe todos; com s\xF3 uma ligada, oferece apenas essa a\xE7\xE3o.",
963
1092
  showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
964
1093
  initialState: "Estado inicial dos accordions",
965
1094
  "states.closed": "Todos fechados",
@@ -968,6 +1097,7 @@ var pt_BR_default = {
968
1097
  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.",
969
1098
  previewUrl: "URL base da rota de preview",
970
1099
  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).",
1100
+ previewUrlEmpty: "Nenhuma URL de preview definida: os editores s\xF3 t\xEAm os modos Campos + p\xE1gina e Editor visual nos tipos de conte\xFAdo com o Preview nativo do Strapi configurado. Nos demais, o menu de modos n\xE3o aparece.",
971
1101
  previewMode: "Modo inicial da preview",
972
1102
  "modes.form": "Campos",
973
1103
  "modes.split": "Campos + p\xE1gina",
@@ -986,8 +1116,6 @@ var pt_BR_default = {
986
1116
  resize: "Redimensionar painel de preview",
987
1117
  resizeHint: "Arraste para redimensionar; clique duplo volta \xE0 metade",
988
1118
  scrollToHovered: "Rolar at\xE9 o bloco destacado",
989
- 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.",
990
- previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
991
1119
  previewFailed: "A preview n\xE3o respondeu em 15 s. Se o frontend ainda estiver carregando, ela aparece sozinha; o formul\xE1rio continua utiliz\xE1vel.",
992
1120
  previewLoading: "Carregando preview\u2026",
993
1121
  retry: "Tentar novamente",
@@ -1132,8 +1260,13 @@ var pt_BR_default = {
1132
1260
  confirmDelete: "Excluir o bloco {name}?",
1133
1261
  confirmDeleteMarker: "Este \xE9 um marcador de grupo: s\xF3 o marcador \xE9 removido, n\xE3o os blocos dentro do grupo, e o grupo fica desbalanceado at\xE9 ser corrigido.",
1134
1262
  delete: "Excluir",
1135
- selectMode: "Selecionar blocos para copiar",
1136
- copySelected: "Copiar selecionados ({count})",
1263
+ selectBlocks: "Selecionar blocos",
1264
+ selectAll: "Selecionar todos",
1265
+ selectNone: "Desmarcar todos",
1266
+ selectedCount: "{count, plural, one {# selecionado} other {# selecionados}}",
1267
+ copy: "Copiar",
1268
+ copyNothing: "Selecione ao menos um bloco para copiar.",
1269
+ selectDone: "Concluir",
1137
1270
  paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
1138
1271
  pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
1139
1272
  copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
@@ -1196,7 +1329,120 @@ var pt_BR_default = {
1196
1329
  historyMax: "Snapshots por documento (m\xE1ximo)",
1197
1330
  historyEventDays: "Manter a atividade (dias)",
1198
1331
  historyRetentionHelp: "Uma rotina noturna esvazia snapshots mais antigos que isso ou al\xE9m do m\xE1ximo por documento (os mais novos s\xE3o mantidos) e exclui a atividade mais antiga que o limite. Nunca exclui arquivos de m\xEDdia.",
1199
- historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots."
1332
+ historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots.",
1333
+ fieldHelp: "Mais informa\xE7\xF5es",
1334
+ paneTitle: "Barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
1335
+ paneHelp: "Os controles marcados aparecem na barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina, nesta ordem. Status e Salvar/Publicar ficam juntos \xE0 direita; os desmarcados ficam ocultos.",
1336
+ "toolbar.modes": "Modo de edi\xE7\xE3o",
1337
+ "toolbar.history": "Desfazer e refazer",
1338
+ "toolbar.devices": "Menu de largura da p\xE1gina",
1339
+ "toolbar.status": "Status do documento",
1340
+ "toolbar.actions": "Salvar e Publicar",
1341
+ paneDevices: "Larguras da p\xE1gina",
1342
+ paneDevicesHelp: "Op\xE7\xF5es do menu de largura, em ordem; a primeira vale at\xE9 o editor escolher outra. Larguras personalizadas: de 240 a 3840 px.",
1343
+ paneAddWidth: "Adicionar largura",
1344
+ paneWidthLabel: "Nome",
1345
+ paneWidth: "Largura (px)",
1346
+ paneRemoveWidth: "Remover largura",
1347
+ paneInvalid: "Mantenha de 1 a 8 larguras, sem repetir; uma largura personalizada precisa de nome (at\xE9 24 caracteres, sem < ou >) e de um n\xFAmero inteiro de 240 a 3840.",
1348
+ paneTypeOverride: "Barra pr\xF3pria da pr\xE9-visualiza\xE7\xE3o para {name}",
1349
+ add: "Adicionar bloco",
1350
+ openAll: "Abrir todos os blocos",
1351
+ closeAll: "Fechar todos os blocos",
1352
+ 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.",
1353
+ previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
1354
+ selectMode: "Selecionar blocos para copiar",
1355
+ copySelected: "Copiar selecionados ({count})",
1356
+ trashDays: "Manter documentos exclu\xEDdos (dias)",
1357
+ trashDaysHelp: "Documentos exclu\xEDdos ficam na lixeira por esse n\xFAmero de dias (fixado quando cada um \xE9 exclu\xEDdo); depois a tarefa noturna os apaga.",
1358
+ "historyActions.purge": "Exclu\xEDdo definitivamente",
1359
+ contentMenu: "Atividade e lixeira",
1360
+ contentTitle: "Atividade de conte\xFAdo e lixeira",
1361
+ contentSubtitle: "Altera\xE7\xF5es feitas pelo Strapi (admin, API, plugins) nos tipos de conte\xFAdo cobertos pelo hist\xF3rico de vers\xF5es.",
1362
+ contentOff: "O hist\xF3rico de vers\xF5es est\xE1 desligado: nada novo \xE9 registrado nem vai para a lixeira. Ligue em Configura\xE7\xF5es, Blockscene.",
1363
+ contentLoading: "Carregando\u2026",
1364
+ contentNone: "\u2014",
1365
+ contentUntitled: "(sem t\xEDtulo)",
1366
+ contentGone: "n\xE3o existe mais",
1367
+ contentOpen: "Abrir",
1368
+ contentPrevious: "Anterior",
1369
+ contentNext: "Pr\xF3xima",
1370
+ contentPage: "P\xE1gina {page} de {pages}, {total} no total",
1371
+ contentClear: "Limpar filtros",
1372
+ activityTab: "Atividade",
1373
+ activityPerson: "Pessoa",
1374
+ activityAnyone: "Qualquer pessoa",
1375
+ activityType: "Tipo de conte\xFAdo",
1376
+ activityAnyType: "Todos os tipos de conte\xFAdo",
1377
+ activityAction: "A\xE7\xE3o",
1378
+ activityAnyAction: "Todas as a\xE7\xF5es",
1379
+ activityFrom: "De",
1380
+ activityTo: "At\xE9",
1381
+ activitySearch: "T\xEDtulo cont\xE9m",
1382
+ activitySearchButton: "Buscar",
1383
+ activityWhen: "Quando",
1384
+ activityDocument: "Documento",
1385
+ activityWho: "Quem",
1386
+ activityWhat: "O qu\xEA",
1387
+ activityEmpty: "Nenhuma atividade corresponde a esses filtros.",
1388
+ activityFailed: "N\xE3o foi poss\xEDvel carregar a atividade.",
1389
+ activityRestoredFrom: "Voltou da lixeira",
1390
+ trashTab: "Lixeira",
1391
+ trashShowRestored: "Mostrar itens restaurados",
1392
+ trashLocales: "Idiomas",
1393
+ trashDeletedBy: "Exclu\xEDdo por",
1394
+ trashDeletedAt: "Exclu\xEDdo",
1395
+ trashExpires: "Exclus\xE3o definitiva",
1396
+ trashExpiresIn: "em {days} dias",
1397
+ trashExpiresToday: "esta noite",
1398
+ trashRestoredAs: "Restaurado",
1399
+ trashEmpty: "A lixeira est\xE1 vazia.",
1400
+ trashFailed: "N\xE3o foi poss\xEDvel carregar a lixeira.",
1401
+ trashPreview: "Visualizar",
1402
+ trashRestore: "Restaurar",
1403
+ trashDelete: "Excluir definitivamente",
1404
+ trashDeleteTitle: "Excluir definitivamente",
1405
+ trashDeleteConfirm: "Excluir \u201C{title}\u201D da lixeira definitivamente? Depois n\xE3o ser\xE1 poss\xEDvel restaur\xE1-lo. Os arquivos de m\xEDdia n\xE3o s\xE3o apagados.",
1406
+ trashDeleted: "Exclu\xEDdo definitivamente.",
1407
+ trashDeleteFailed: "N\xE3o foi poss\xEDvel excluir.",
1408
+ trashDraft: "rascunho",
1409
+ trashPublished: "publicado",
1410
+ trashFields: "Campos",
1411
+ trashBlocks: "Blocos",
1412
+ trashItems: "{count} item(ns)",
1413
+ trashIncoming: "{count} v\xEDnculo(s) de outros documentos ou blocos foram guardados.",
1414
+ trashClose: "Fechar",
1415
+ restoreTitle: "Restaurar \u201C{title}\u201D",
1416
+ restoreChecking: "Verificando o que a restaura\xE7\xE3o faria\u2026",
1417
+ restoreIntro: "O documento volta como rascunho, com o conte\xFAdo do rascunho: confira e publique de novo.",
1418
+ restoreNew: "Um novo documento \xE9 criado (o Strapi n\xE3o reaproveita o id original).",
1419
+ restoreInto: "Os idiomas voltam para o documento que j\xE1 existe.",
1420
+ restoreLocales: "Idiomas restaurados: {locales}",
1421
+ restoreBlocked: "N\xE3o \xE9 poss\xEDvel restaurar como est\xE1 (nada \xE9 gravado):",
1422
+ restoreWarnings: "Ele \xE9 restaurado com estas diferen\xE7as:",
1423
+ restoreConfirm: "Restaurar como rascunho",
1424
+ restoreCancel: "Cancelar",
1425
+ restoreDone: "Restaurado como rascunho.",
1426
+ restoreAlready: "Este item j\xE1 foi restaurado.",
1427
+ restoreFailed: "A restaura\xE7\xE3o falhou: nada foi gravado.",
1428
+ restoreOpen: "Abrir o documento restaurado",
1429
+ "report.typeGone": "O tipo de conte\xFAdo n\xE3o existe mais.",
1430
+ "report.localeExists": "O documento j\xE1 tem o idioma {locale} de novo.",
1431
+ "report.unique": "\u201C{value}\u201D j\xE1 \xE9 usado em {field} ({locale}) por outro documento.",
1432
+ "report.singleExists": "Este tipo \xFAnico j\xE1 tem um documento de novo.",
1433
+ "report.nothing": "N\xE3o h\xE1 nada para restaurar: nenhum dos idiomas est\xE1 mais configurado.",
1434
+ "report.restored": "J\xE1 restaurado.",
1435
+ "report.published": "Havia uma vers\xE3o publicada ({locales}): ela fica guardada no item da lixeira; o que volta \xE9 o rascunho.",
1436
+ "report.localeRemoved": "O idioma {locale} n\xE3o est\xE1 mais configurado: ignorado.",
1437
+ "report.required": "Campos obrigat\xF3rios vazios ({locale}): {fields}. Preencha antes de publicar.",
1438
+ "report.fieldsRemoved": "Campos que o schema n\xE3o tem mais, deixados de fora ({locale}): {fields}.",
1439
+ "report.media": "{count} arquivo(s) de m\xEDdia n\xE3o existem mais, deixados vazios ({locale}).",
1440
+ "report.relations": "{count} documento(s) relacionados n\xE3o existem mais, deixados de fora ({locale}).",
1441
+ "report.blocks": "{count} bloco(s) cujo componente a zona n\xE3o permite mais, deixados de fora ({locale}).",
1442
+ "report.incoming": "V\xEDnculos de outros documentos e blocos: {reconnect} recolocados, {gone} cujo dono n\xE3o existe mais, {replaced} cujo dono agora aponta para outro, {published} de vers\xF5es publicadas (voltam quando esses documentos forem publicados de novo).",
1443
+ groupCollapse: "Recolher grupo {label}",
1444
+ groupExpand: "Expandir grupo {label}",
1445
+ groupBlocks: "{count, plural, one {# bloco} other {# blocos}}"
1200
1446
  };
1201
1447
 
1202
1448
  // admin/translations/pt.json
@@ -1204,7 +1450,6 @@ var pt_default = {
1204
1450
  title: "Blockscene",
1205
1451
  settings: "Galeria",
1206
1452
  gallery: "Galeria de blocos",
1207
- add: "Adicionar bloco",
1208
1453
  search: "Pesquisar blocos",
1209
1454
  clear: "Limpar pesquisa",
1210
1455
  empty: "Nenhum bloco encontrado.",
@@ -1214,8 +1459,9 @@ var pt_default = {
1214
1459
  failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
1215
1460
  insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
1216
1461
  example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
1217
- openAll: "Abrir todos os blocos",
1218
- closeAll: "Fechar todos os blocos",
1462
+ expandAll: "Expandir tudo",
1463
+ collapseAll: "Recolher tudo",
1464
+ moreActions: "Mais a\xE7\xF5es",
1219
1465
  settingsTitle: "Blockscene",
1220
1466
  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.",
1221
1467
  palette: "Paleta dos wireframes",
@@ -1243,8 +1489,9 @@ var pt_default = {
1243
1489
  editor: "Prefer\xEAncias do editor",
1244
1490
  enabled: "Blockscene ligado",
1245
1491
  enabledHelp: "Desligado, o plugin inteiro para de imediato, sem rein\xEDcio: todos os ecr\xE3s de edi\xE7\xE3o voltam a ser nativos e a verifica\xE7\xE3o de grupos na publica\xE7\xE3o para. Use-o se algo correr mal em produ\xE7\xE3o.",
1246
- showOpenAll: 'Mostrar "Abrir todos os blocos"',
1247
- showCloseAll: 'Mostrar "Fechar todos os blocos"',
1492
+ showOpenAll: 'Mostrar "Expandir tudo"',
1493
+ showCloseAll: 'Mostrar "Recolher tudo"',
1494
+ toggleHelp: "A barra da zona mostra um \xFAnico bot\xE3o: com as duas op\xE7\xF5es ativas, expande enquanto houver algum bloco recolhido e, caso contr\xE1rio, recolhe todos; com apenas uma ativa, oferece s\xF3 essa a\xE7\xE3o.",
1248
1495
  showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
1249
1496
  initialState: "Estado inicial dos accordions",
1250
1497
  "states.closed": "Todos fechados",
@@ -1253,6 +1500,7 @@ var pt_default = {
1253
1500
  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.",
1254
1501
  previewUrl: "URL base da rota de pr\xE9-visualiza\xE7\xE3o",
1255
1502
  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).",
1503
+ previewUrlEmpty: "Nenhum URL de pr\xE9-visualiza\xE7\xE3o definido: os editores s\xF3 t\xEAm os modos Campos + p\xE1gina e Editor visual nos tipos de conte\xFAdo com a Preview nativa do Strapi configurada. Nos restantes, o menu de modos n\xE3o aparece.",
1256
1504
  previewMode: "Modo inicial da pr\xE9-visualiza\xE7\xE3o",
1257
1505
  "modes.form": "Campos",
1258
1506
  "modes.split": "Campos + p\xE1gina",
@@ -1271,8 +1519,6 @@ var pt_default = {
1271
1519
  resize: "Redimensionar painel de pr\xE9-visualiza\xE7\xE3o",
1272
1520
  resizeHint: "Arraste para redimensionar; duplo clique rep\xF5e a metade",
1273
1521
  scrollToHovered: "Deslocar at\xE9 ao bloco destacado",
1274
- 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.",
1275
- 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.",
1276
1522
  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.",
1277
1523
  previewLoading: "A carregar pr\xE9-visualiza\xE7\xE3o\u2026",
1278
1524
  retry: "Tentar novamente",
@@ -1417,8 +1663,13 @@ var pt_default = {
1417
1663
  confirmDelete: "Eliminar o bloco {name}?",
1418
1664
  confirmDeleteMarker: "Este \xE9 um marcador de grupo: s\xF3 o marcador \xE9 removido, n\xE3o os blocos dentro do grupo, e o grupo fica desequilibrado at\xE9 ser corrigido.",
1419
1665
  delete: "Eliminar",
1420
- selectMode: "Selecionar blocos para copiar",
1421
- copySelected: "Copiar selecionados ({count})",
1666
+ selectBlocks: "Selecionar blocos",
1667
+ selectAll: "Selecionar todos",
1668
+ selectNone: "Desmarcar todos",
1669
+ selectedCount: "{count, plural, one {# selecionado} other {# selecionados}}",
1670
+ copy: "Copiar",
1671
+ copyNothing: "Selecione pelo menos um bloco para copiar.",
1672
+ selectDone: "Concluir",
1422
1673
  paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
1423
1674
  pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
1424
1675
  copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
@@ -1481,7 +1732,120 @@ var pt_default = {
1481
1732
  historyMax: "Snapshots por documento (m\xE1ximo)",
1482
1733
  historyEventDays: "Manter a atividade (dias)",
1483
1734
  historyRetentionHelp: "Uma tarefa noturna esvazia os snapshots mais antigos do que isto ou al\xE9m do m\xE1ximo por documento (os mais recentes s\xE3o mantidos) e elimina a atividade mais antiga do que o limite. Nunca elimina ficheiros multim\xE9dia.",
1484
- historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots."
1735
+ historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots.",
1736
+ fieldHelp: "Mais informa\xE7\xF5es",
1737
+ paneTitle: "Barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
1738
+ paneHelp: "Os controlos marcados aparecem na barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina, por esta ordem. Estado e Guardar/Publicar ficam juntos \xE0 direita; os desmarcados ficam ocultos.",
1739
+ "toolbar.modes": "Modo de edi\xE7\xE3o",
1740
+ "toolbar.history": "Anular e refazer",
1741
+ "toolbar.devices": "Menu de largura da p\xE1gina",
1742
+ "toolbar.status": "Estado do documento",
1743
+ "toolbar.actions": "Guardar e Publicar",
1744
+ paneDevices: "Larguras da p\xE1gina",
1745
+ paneDevicesHelp: "Op\xE7\xF5es do menu de largura, por ordem; a primeira vale at\xE9 o editor escolher outra. Larguras personalizadas: de 240 a 3840 px.",
1746
+ paneAddWidth: "Adicionar largura",
1747
+ paneWidthLabel: "Nome",
1748
+ paneWidth: "Largura (px)",
1749
+ paneRemoveWidth: "Remover largura",
1750
+ paneInvalid: "Mantenha de 1 a 8 larguras, sem repetir; uma largura personalizada precisa de nome (at\xE9 24 caracteres, sem < ou >) e de um n\xFAmero inteiro de 240 a 3840.",
1751
+ paneTypeOverride: "Barra pr\xF3pria da pr\xE9-visualiza\xE7\xE3o para {name}",
1752
+ add: "Adicionar bloco",
1753
+ openAll: "Abrir todos os blocos",
1754
+ closeAll: "Fechar todos os blocos",
1755
+ 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.",
1756
+ 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.",
1757
+ selectMode: "Selecionar blocos para copiar",
1758
+ copySelected: "Copiar selecionados ({count})",
1759
+ trashDays: "Manter documentos eliminados (dias)",
1760
+ trashDaysHelp: "Os documentos eliminados ficam no lixo durante esse n\xFAmero de dias (fixado quando cada um \xE9 eliminado); depois a tarefa noturna apaga-os.",
1761
+ "historyActions.purge": "Eliminado definitivamente",
1762
+ contentMenu: "Atividade e lixo",
1763
+ contentTitle: "Atividade de conte\xFAdo e lixo",
1764
+ contentSubtitle: "Altera\xE7\xF5es feitas atrav\xE9s do Strapi (admin, API, plugins) nos tipos de conte\xFAdo abrangidos pelo hist\xF3rico de vers\xF5es.",
1765
+ contentOff: "O hist\xF3rico de vers\xF5es est\xE1 desligado: nada de novo \xE9 registado nem vai para o lixo. Ligue-o em Defini\xE7\xF5es, Blockscene.",
1766
+ contentLoading: "A carregar\u2026",
1767
+ contentNone: "\u2014",
1768
+ contentUntitled: "(sem t\xEDtulo)",
1769
+ contentGone: "j\xE1 n\xE3o existe",
1770
+ contentOpen: "Abrir",
1771
+ contentPrevious: "Anterior",
1772
+ contentNext: "Seguinte",
1773
+ contentPage: "P\xE1gina {page} de {pages}, {total} no total",
1774
+ contentClear: "Limpar filtros",
1775
+ activityTab: "Atividade",
1776
+ activityPerson: "Pessoa",
1777
+ activityAnyone: "Qualquer pessoa",
1778
+ activityType: "Tipo de conte\xFAdo",
1779
+ activityAnyType: "Todos os tipos de conte\xFAdo",
1780
+ activityAction: "A\xE7\xE3o",
1781
+ activityAnyAction: "Todas as a\xE7\xF5es",
1782
+ activityFrom: "De",
1783
+ activityTo: "At\xE9",
1784
+ activitySearch: "T\xEDtulo cont\xE9m",
1785
+ activitySearchButton: "Pesquisar",
1786
+ activityWhen: "Quando",
1787
+ activityDocument: "Documento",
1788
+ activityWho: "Quem",
1789
+ activityWhat: "O qu\xEA",
1790
+ activityEmpty: "Nenhuma atividade corresponde a estes filtros.",
1791
+ activityFailed: "N\xE3o foi poss\xEDvel carregar a atividade.",
1792
+ activityRestoredFrom: "Recuperado do lixo",
1793
+ trashTab: "Lixo",
1794
+ trashShowRestored: "Mostrar entradas restauradas",
1795
+ trashLocales: "Idiomas",
1796
+ trashDeletedBy: "Eliminado por",
1797
+ trashDeletedAt: "Eliminado",
1798
+ trashExpires: "Elimina\xE7\xE3o definitiva",
1799
+ trashExpiresIn: "daqui a {days} dias",
1800
+ trashExpiresToday: "esta noite",
1801
+ trashRestoredAs: "Restaurado",
1802
+ trashEmpty: "O lixo est\xE1 vazio.",
1803
+ trashFailed: "N\xE3o foi poss\xEDvel carregar o lixo.",
1804
+ trashPreview: "Pr\xE9-visualizar",
1805
+ trashRestore: "Restaurar",
1806
+ trashDelete: "Eliminar definitivamente",
1807
+ trashDeleteTitle: "Eliminar definitivamente",
1808
+ trashDeleteConfirm: "Eliminar \u201C{title}\u201D do lixo definitivamente? Depois n\xE3o poder\xE1 ser restaurado. Os ficheiros multim\xE9dia n\xE3o s\xE3o apagados.",
1809
+ trashDeleted: "Eliminado definitivamente.",
1810
+ trashDeleteFailed: "N\xE3o foi poss\xEDvel eliminar.",
1811
+ trashDraft: "rascunho",
1812
+ trashPublished: "publicado",
1813
+ trashFields: "Campos",
1814
+ trashBlocks: "Blocos",
1815
+ trashItems: "{count} item(ns)",
1816
+ trashIncoming: "{count} liga\xE7\xE3o(\xF5es) de outros documentos ou blocos foram guardadas.",
1817
+ trashClose: "Fechar",
1818
+ restoreTitle: "Restaurar \u201C{title}\u201D",
1819
+ restoreChecking: "A verificar o que o restauro faria\u2026",
1820
+ restoreIntro: "O documento volta como rascunho, com o conte\xFAdo do rascunho: reveja-o e publique-o novamente.",
1821
+ restoreNew: "\xC9 criado um documento novo (o Strapi n\xE3o reutiliza o id original).",
1822
+ restoreInto: "Os idiomas voltam ao documento que j\xE1 existe.",
1823
+ restoreLocales: "Idiomas restaurados: {locales}",
1824
+ restoreBlocked: "N\xE3o pode ser restaurado tal como est\xE1 (nada \xE9 gravado):",
1825
+ restoreWarnings: "\xC9 restaurado com estas diferen\xE7as:",
1826
+ restoreConfirm: "Restaurar como rascunho",
1827
+ restoreCancel: "Cancelar",
1828
+ restoreDone: "Restaurado como rascunho.",
1829
+ restoreAlready: "Esta entrada j\xE1 foi restaurada.",
1830
+ restoreFailed: "O restauro falhou: nada foi gravado.",
1831
+ restoreOpen: "Abrir o documento restaurado",
1832
+ "report.typeGone": "O tipo de conte\xFAdo j\xE1 n\xE3o existe.",
1833
+ "report.localeExists": "O documento voltou a ter o idioma {locale}.",
1834
+ "report.unique": "\u201C{value}\u201D j\xE1 \xE9 usado em {field} ({locale}) por outro documento.",
1835
+ "report.singleExists": "Este tipo \xFAnico voltou a ter um documento.",
1836
+ "report.nothing": "Nada a restaurar: nenhum dos idiomas continua configurado.",
1837
+ "report.restored": "J\xE1 restaurado.",
1838
+ "report.published": "Existia uma vers\xE3o publicada ({locales}): fica guardada na entrada do lixo; o que volta \xE9 o rascunho.",
1839
+ "report.localeRemoved": "O idioma {locale} j\xE1 n\xE3o est\xE1 configurado: ignorado.",
1840
+ "report.required": "Campos obrigat\xF3rios vazios ({locale}): {fields}. Preencha-os antes de publicar.",
1841
+ "report.fieldsRemoved": "Campos que o esquema j\xE1 n\xE3o tem, deixados de fora ({locale}): {fields}.",
1842
+ "report.media": "{count} ficheiro(s) multim\xE9dia j\xE1 n\xE3o existem, deixados vazios ({locale}).",
1843
+ "report.relations": "{count} documento(s) relacionados j\xE1 n\xE3o existem, deixados de fora ({locale}).",
1844
+ "report.blocks": "{count} bloco(s) cujo componente a zona j\xE1 n\xE3o permite, deixados de fora ({locale}).",
1845
+ "report.incoming": "Liga\xE7\xF5es de outros documentos e blocos: {reconnect} repostas, {gone} cujo dono j\xE1 n\xE3o existe, {replaced} cujo dono aponta agora para outro, {published} de vers\xF5es publicadas (voltam quando esses documentos forem publicados novamente).",
1846
+ groupCollapse: "Recolher grupo {label}",
1847
+ groupExpand: "Expandir grupo {label}",
1848
+ groupBlocks: "{count, plural, one {# bloco} other {# blocos}}"
1485
1849
  };
1486
1850
 
1487
1851
  // admin/translations/fr.json
@@ -1489,7 +1853,6 @@ var fr_default = {
1489
1853
  title: "Blockscene",
1490
1854
  settings: "Galerie",
1491
1855
  gallery: "Galerie de blocs",
1492
- add: "Ajouter un bloc",
1493
1856
  search: "Rechercher des blocs",
1494
1857
  clear: "Effacer la recherche",
1495
1858
  empty: "Aucun bloc trouv\xE9.",
@@ -1499,8 +1862,9 @@ var fr_default = {
1499
1862
  failed: "Impossible de charger le catalogue. Fermez et r\xE9essayez.",
1500
1863
  insertFailed: "Impossible de cr\xE9er ce composant. Utilisez le s\xE9lecteur natif et signalez son sch\xE9ma.",
1501
1864
  example: "Les images sont des exemples ; l'apparence d\xE9pend de votre frontend.",
1502
- openAll: "Ouvrir tous les blocs",
1503
- closeAll: "Fermer tous les blocs",
1865
+ expandAll: "Tout d\xE9plier",
1866
+ collapseAll: "Tout replier",
1867
+ moreActions: "Plus d'actions",
1504
1868
  settingsTitle: "Blockscene",
1505
1869
  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.",
1506
1870
  palette: "Palette des wireframes",
@@ -1528,8 +1892,9 @@ var fr_default = {
1528
1892
  editor: "Pr\xE9f\xE9rences de l'\xE9diteur",
1529
1893
  enabled: "Blockscene activ\xE9",
1530
1894
  enabledHelp: "D\xE9sactiv\xE9, tout le plugin s'arr\xEAte aussit\xF4t, sans red\xE9marrage : chaque vue d'\xE9dition redevient native et la v\xE9rification des groupes \xE0 la publication s'arr\xEAte. \xC0 utiliser si quelque chose se passe mal en production.",
1531
- showOpenAll: "Afficher \xAB Ouvrir tous les blocs \xBB",
1532
- showCloseAll: "Afficher \xAB Fermer tous les blocs \xBB",
1895
+ showOpenAll: "Afficher \xAB Tout d\xE9plier \xBB",
1896
+ showCloseAll: "Afficher \xAB Tout replier \xBB",
1897
+ toggleHelp: "La barre de la zone affiche un seul bouton : avec les deux options activ\xE9es, il d\xE9plie tant qu'un bloc est repli\xE9 et sinon les replie tous ; avec une seule, il ne propose que cette action.",
1533
1898
  showRowThumbnails: "Afficher les miniatures des blocs dans les lignes",
1534
1899
  initialState: "\xC9tat initial des accord\xE9ons",
1535
1900
  "states.closed": "Tous ferm\xE9s",
@@ -1538,6 +1903,7 @@ var fr_default = {
1538
1903
  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.",
1539
1904
  previewUrl: "URL de base de la route d'aper\xE7u",
1540
1905
  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).",
1906
+ previewUrlEmpty: "Aucune URL d'aper\xE7u : les \xE9diteurs n'ont les modes Champs + page et \xC9diteur visuel que sur les types de contenu o\xF9 l'aper\xE7u natif de Strapi est configur\xE9. Ailleurs, le menu des modes n'appara\xEEt pas.",
1541
1907
  previewMode: "Mode d'aper\xE7u initial",
1542
1908
  "modes.form": "Champs",
1543
1909
  "modes.split": "Champs + page",
@@ -1556,8 +1922,6 @@ var fr_default = {
1556
1922
  resize: "Redimensionner le panneau d'aper\xE7u",
1557
1923
  resizeHint: "Faites glisser pour redimensionner ; double-clic pour revenir \xE0 la moiti\xE9",
1558
1924
  scrollToHovered: "Faire d\xE9filer jusqu\u2019au bloc en surbrillance",
1559
- 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.",
1560
- 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.",
1561
1925
  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.",
1562
1926
  previewLoading: "Chargement de l'aper\xE7u\u2026",
1563
1927
  retry: "R\xE9essayer",
@@ -1702,8 +2066,13 @@ var fr_default = {
1702
2066
  confirmDelete: "Supprimer le bloc {name} ?",
1703
2067
  confirmDeleteMarker: "C'est un marqueur de groupe : seul le marqueur est supprim\xE9, pas les blocs du groupe, et le groupe reste d\xE9s\xE9quilibr\xE9 jusqu'\xE0 sa correction.",
1704
2068
  delete: "Supprimer",
1705
- selectMode: "S\xE9lectionner des blocs \xE0 copier",
1706
- copySelected: "Copier la s\xE9lection ({count})",
2069
+ selectBlocks: "S\xE9lectionner des blocs",
2070
+ selectAll: "Tout s\xE9lectionner",
2071
+ selectNone: "Tout d\xE9s\xE9lectionner",
2072
+ selectedCount: "{count, plural, one {# s\xE9lectionn\xE9} other {# s\xE9lectionn\xE9s}}",
2073
+ copy: "Copier",
2074
+ copyNothing: "S\xE9lectionnez au moins un bloc \xE0 copier.",
2075
+ selectDone: "Termin\xE9",
1707
2076
  paste: "Coller {count, plural, one {# bloc} other {# blocs}}",
1708
2077
  pasted: "{count, plural, one {# bloc coll\xE9} other {# blocs coll\xE9s}}.",
1709
2078
  copied: "{count, plural, one {# bloc copi\xE9} other {# blocs copi\xE9s}}. Collez-les sur n'importe quelle page de ce site.",
@@ -1766,7 +2135,120 @@ var fr_default = {
1766
2135
  historyMax: "Instantan\xE9s par document (maximum)",
1767
2136
  historyEventDays: "Conserver l'activit\xE9 (jours)",
1768
2137
  historyRetentionHelp: "Une t\xE2che nocturne vide les instantan\xE9s plus anciens que cela ou au-del\xE0 du maximum par document (les plus r\xE9cents sont gard\xE9s) et supprime l'activit\xE9 plus ancienne que sa limite. Elle ne supprime jamais de fichiers m\xE9dia.",
1769
- historyInvalid: "Nombres entiers : 1 \xE0 3650 jours (l'activit\xE9 conserv\xE9e au moins aussi longtemps que les instantan\xE9s) et 1 \xE0 1000 instantan\xE9s."
2138
+ historyInvalid: "Nombres entiers : 1 \xE0 3650 jours (l'activit\xE9 conserv\xE9e au moins aussi longtemps que les instantan\xE9s) et 1 \xE0 1000 instantan\xE9s.",
2139
+ fieldHelp: "Plus d'informations",
2140
+ paneTitle: "Barre de l'aper\xE7u de page",
2141
+ paneHelp: "Les contr\xF4les coch\xE9s apparaissent dans la barre de l'aper\xE7u de page, dans cet ordre. Statut et Enregistrer/Publier restent ensemble \xE0 droite ; les autres sont masqu\xE9s.",
2142
+ "toolbar.modes": "Mode d'\xE9dition",
2143
+ "toolbar.history": "Annuler et r\xE9tablir",
2144
+ "toolbar.devices": "Menu de largeur de page",
2145
+ "toolbar.status": "Statut du document",
2146
+ "toolbar.actions": "Enregistrer et Publier",
2147
+ paneDevices: "Largeurs de page",
2148
+ paneDevicesHelp: "Entr\xE9es du menu de largeur, dans l'ordre ; la premi\xE8re s'applique tant que l'\xE9diteur n'en choisit pas une autre. Largeurs personnalis\xE9es : de 240 \xE0 3840 px.",
2149
+ paneAddWidth: "Ajouter une largeur",
2150
+ paneWidthLabel: "Libell\xE9",
2151
+ paneWidth: "Largeur (px)",
2152
+ paneRemoveWidth: "Retirer la largeur",
2153
+ paneInvalid: "Gardez de 1 \xE0 8 largeurs, sans doublon ; une largeur personnalis\xE9e demande un libell\xE9 (24 caract\xE8res au plus, sans < ni >) et un nombre entier de 240 \xE0 3840.",
2154
+ paneTypeOverride: "Barre d'aper\xE7u propre \xE0 {name}",
2155
+ add: "Ajouter un bloc",
2156
+ openAll: "Ouvrir tous les blocs",
2157
+ closeAll: "Fermer tous les blocs",
2158
+ 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.",
2159
+ 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.",
2160
+ selectMode: "S\xE9lectionner des blocs \xE0 copier",
2161
+ copySelected: "Copier la s\xE9lection ({count})",
2162
+ trashDays: "Conserver les documents supprim\xE9s (jours)",
2163
+ trashDaysHelp: "Les documents supprim\xE9s restent dans la corbeille ce nombre de jours (fix\xE9 lors de chaque suppression), puis la t\xE2che nocturne les efface.",
2164
+ "historyActions.purge": "Supprim\xE9 d\xE9finitivement",
2165
+ contentMenu: "Activit\xE9 et corbeille",
2166
+ contentTitle: "Activit\xE9 du contenu et corbeille",
2167
+ contentSubtitle: "Modifications faites via Strapi (admin, API, plugins) sur les types de contenu couverts par l'historique des versions.",
2168
+ contentOff: "L'historique des versions est d\xE9sactiv\xE9 : rien de nouveau n'est enregistr\xE9 ni mis \xE0 la corbeille. Activez-le dans Param\xE8tres, Blockscene.",
2169
+ contentLoading: "Chargement\u2026",
2170
+ contentNone: "\u2014",
2171
+ contentUntitled: "(sans titre)",
2172
+ contentGone: "n'existe plus",
2173
+ contentOpen: "Ouvrir",
2174
+ contentPrevious: "Pr\xE9c\xE9dent",
2175
+ contentNext: "Suivant",
2176
+ contentPage: "Page {page} sur {pages}, {total} au total",
2177
+ contentClear: "Effacer les filtres",
2178
+ activityTab: "Activit\xE9",
2179
+ activityPerson: "Personne",
2180
+ activityAnyone: "Tout le monde",
2181
+ activityType: "Type de contenu",
2182
+ activityAnyType: "Tous les types de contenu",
2183
+ activityAction: "Action",
2184
+ activityAnyAction: "Toutes les actions",
2185
+ activityFrom: "Du",
2186
+ activityTo: "Au",
2187
+ activitySearch: "Le titre contient",
2188
+ activitySearchButton: "Rechercher",
2189
+ activityWhen: "Quand",
2190
+ activityDocument: "Document",
2191
+ activityWho: "Qui",
2192
+ activityWhat: "Quoi",
2193
+ activityEmpty: "Aucune activit\xE9 ne correspond \xE0 ces filtres.",
2194
+ activityFailed: "L'activit\xE9 n'a pas pu \xEAtre charg\xE9e.",
2195
+ activityRestoredFrom: "Sorti de la corbeille",
2196
+ trashTab: "Corbeille",
2197
+ trashShowRestored: "Afficher les entr\xE9es restaur\xE9es",
2198
+ trashLocales: "Langues",
2199
+ trashDeletedBy: "Supprim\xE9 par",
2200
+ trashDeletedAt: "Supprim\xE9",
2201
+ trashExpires: "Suppression d\xE9finitive",
2202
+ trashExpiresIn: "dans {days} jours",
2203
+ trashExpiresToday: "cette nuit",
2204
+ trashRestoredAs: "Restaur\xE9",
2205
+ trashEmpty: "La corbeille est vide.",
2206
+ trashFailed: "La corbeille n'a pas pu \xEAtre charg\xE9e.",
2207
+ trashPreview: "Aper\xE7u",
2208
+ trashRestore: "Restaurer",
2209
+ trashDelete: "Supprimer d\xE9finitivement",
2210
+ trashDeleteTitle: "Supprimer d\xE9finitivement",
2211
+ trashDeleteConfirm: "Supprimer \xAB {title} \xBB de la corbeille d\xE9finitivement ? Il ne pourra plus \xEAtre restaur\xE9. Les fichiers m\xE9dia ne sont pas supprim\xE9s.",
2212
+ trashDeleted: "Supprim\xE9 d\xE9finitivement.",
2213
+ trashDeleteFailed: "La suppression a \xE9chou\xE9.",
2214
+ trashDraft: "brouillon",
2215
+ trashPublished: "publi\xE9",
2216
+ trashFields: "Champs",
2217
+ trashBlocks: "Blocs",
2218
+ trashItems: "{count} \xE9l\xE9ment(s)",
2219
+ trashIncoming: "{count} lien(s) depuis d'autres documents ou blocs ont \xE9t\xE9 conserv\xE9s.",
2220
+ trashClose: "Fermer",
2221
+ restoreTitle: "Restaurer \xAB {title} \xBB",
2222
+ restoreChecking: "V\xE9rification de ce que ferait la restauration\u2026",
2223
+ restoreIntro: "Le document revient en brouillon, avec le contenu du brouillon : v\xE9rifiez-le, puis publiez-le \xE0 nouveau.",
2224
+ restoreNew: "Un nouveau document est cr\xE9\xE9 (Strapi ne r\xE9utilise pas l'id d'origine).",
2225
+ restoreInto: "Les langues reviennent dans le document existant.",
2226
+ restoreLocales: "Langues restaur\xE9es : {locales}",
2227
+ restoreBlocked: "Il ne peut pas \xEAtre restaur\xE9 en l'\xE9tat (rien n'est \xE9crit) :",
2228
+ restoreWarnings: "Il est restaur\xE9 avec ces diff\xE9rences :",
2229
+ restoreConfirm: "Restaurer en brouillon",
2230
+ restoreCancel: "Annuler",
2231
+ restoreDone: "Restaur\xE9 en brouillon.",
2232
+ restoreAlready: "Cette entr\xE9e a d\xE9j\xE0 \xE9t\xE9 restaur\xE9e.",
2233
+ restoreFailed: "La restauration a \xE9chou\xE9 : rien n'a \xE9t\xE9 \xE9crit.",
2234
+ restoreOpen: "Ouvrir le document restaur\xE9",
2235
+ "report.typeGone": "Le type de contenu n'existe plus.",
2236
+ "report.localeExists": "Le document a de nouveau la langue {locale}.",
2237
+ "report.unique": "\xAB {value} \xBB est d\xE9j\xE0 utilis\xE9 dans {field} ({locale}) par un autre document.",
2238
+ "report.singleExists": "Ce type unique a de nouveau un document.",
2239
+ "report.nothing": "Rien \xE0 restaurer : aucune de ses langues n'est encore configur\xE9e.",
2240
+ "report.restored": "D\xE9j\xE0 restaur\xE9.",
2241
+ "report.published": "Une version publi\xE9e existait ({locales}) : elle reste dans l'entr\xE9e de la corbeille, c'est le brouillon qui revient.",
2242
+ "report.localeRemoved": "La langue {locale} n'est plus configur\xE9e : ignor\xE9e.",
2243
+ "report.required": "Champs obligatoires vides ({locale}) : {fields}. Remplissez-les avant de publier.",
2244
+ "report.fieldsRemoved": "Champs que le sch\xE9ma n'a plus, laiss\xE9s de c\xF4t\xE9 ({locale}) : {fields}.",
2245
+ "report.media": "{count} fichier(s) m\xE9dia n'existent plus, laiss\xE9s vides ({locale}).",
2246
+ "report.relations": "{count} document(s) li\xE9s n'existent plus, laiss\xE9s de c\xF4t\xE9 ({locale}).",
2247
+ "report.blocks": "{count} bloc(s) dont la zone n'autorise plus le composant, laiss\xE9s de c\xF4t\xE9 ({locale}).",
2248
+ "report.incoming": "Liens depuis d'autres documents et blocs : {reconnect} remis en place, {gone} dont le propri\xE9taire n'existe plus, {replaced} dont le propri\xE9taire pointe d\xE9sormais ailleurs, {published} depuis des versions publi\xE9es (ils reviennent quand ces documents sont republi\xE9s).",
2249
+ groupCollapse: "Replier le groupe {label}",
2250
+ groupExpand: "D\xE9plier le groupe {label}",
2251
+ groupBlocks: "{count, plural, one {# bloc} other {# blocs}}"
1770
2252
  };
1771
2253
 
1772
2254
  // admin/translations/es.json
@@ -1774,7 +2256,6 @@ var es_default = {
1774
2256
  title: "Blockscene",
1775
2257
  settings: "Galer\xEDa",
1776
2258
  gallery: "Galer\xEDa de bloques",
1777
- add: "A\xF1adir bloque",
1778
2259
  search: "Buscar bloques",
1779
2260
  clear: "Borrar b\xFAsqueda",
1780
2261
  empty: "No se encontraron bloques.",
@@ -1784,8 +2265,9 @@ var es_default = {
1784
2265
  failed: "No se pudo cargar el cat\xE1logo. Cierre e int\xE9ntelo de nuevo.",
1785
2266
  insertFailed: "No se pudo crear este componente. Use el selector nativo e informe de su esquema.",
1786
2267
  example: "Las im\xE1genes son ejemplos; la apariencia depende de su frontend.",
1787
- openAll: "Abrir todos los bloques",
1788
- closeAll: "Cerrar todos los bloques",
2268
+ expandAll: "Expandir todo",
2269
+ collapseAll: "Contraer todo",
2270
+ moreActions: "M\xE1s acciones",
1789
2271
  settingsTitle: "Blockscene",
1790
2272
  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.",
1791
2273
  palette: "Paleta de wireframes",
@@ -1813,8 +2295,9 @@ var es_default = {
1813
2295
  editor: "Preferencias del editor",
1814
2296
  enabled: "Blockscene activado",
1815
2297
  enabledHelp: "Desactivado, todo el plugin se detiene al instante, sin reinicio: cada vista de edici\xF3n vuelve a ser nativa y se detiene la verificaci\xF3n de grupos al publicar. \xDAsalo si algo falla en producci\xF3n.",
1816
- showOpenAll: "Mostrar \xABAbrir todos los bloques\xBB",
1817
- showCloseAll: "Mostrar \xABCerrar todos los bloques\xBB",
2298
+ showOpenAll: "Mostrar \xABExpandir todo\xBB",
2299
+ showCloseAll: "Mostrar \xABContraer todo\xBB",
2300
+ toggleHelp: "La barra de la zona muestra un solo bot\xF3n: con ambas opciones activadas expande mientras haya alg\xFAn bloque contra\xEDdo y, si no, los contrae todos; con solo una, ofrece \xFAnicamente esa acci\xF3n.",
1818
2301
  showRowThumbnails: "Mostrar miniaturas de los bloques en las filas",
1819
2302
  initialState: "Estado inicial de los acordeones",
1820
2303
  "states.closed": "Todos cerrados",
@@ -1823,6 +2306,7 @@ var es_default = {
1823
2306
  rememberHelp: "Solo los botones expl\xEDcitos de abrir/cerrar todos actualizan la memoria, por usuario y navegador. Abrir un solo bloque no la cambia.",
1824
2307
  previewUrl: "URL base de la ruta de vista previa",
1825
2308
  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).",
2309
+ previewUrlEmpty: "No hay URL de vista previa: los editores solo tienen los modos Campos + p\xE1gina y Editor visual en los tipos de contenido con la vista previa nativa de Strapi configurada. En los dem\xE1s no aparece el men\xFA de modos.",
1826
2310
  previewMode: "Modo inicial de la vista previa",
1827
2311
  "modes.form": "Campos",
1828
2312
  "modes.split": "Campos + p\xE1gina",
@@ -1841,8 +2325,6 @@ var es_default = {
1841
2325
  resize: "Redimensionar el panel de vista previa",
1842
2326
  resizeHint: "Arrastra para redimensionar; doble clic vuelve a la mitad",
1843
2327
  scrollToHovered: "Desplazarse al bloque resaltado",
1844
- 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.",
1845
- previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
1846
2328
  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.",
1847
2329
  previewLoading: "Cargando vista previa\u2026",
1848
2330
  retry: "Reintentar",
@@ -1987,8 +2469,13 @@ var es_default = {
1987
2469
  confirmDelete: "\xBFEliminar el bloque {name}?",
1988
2470
  confirmDeleteMarker: "Es un marcador de grupo: solo se elimina el marcador, no los bloques del grupo, y el grupo queda desequilibrado hasta corregirlo.",
1989
2471
  delete: "Eliminar",
1990
- selectMode: "Seleccionar bloques para copiar",
1991
- copySelected: "Copiar seleccionados ({count})",
2472
+ selectBlocks: "Seleccionar bloques",
2473
+ selectAll: "Seleccionar todos",
2474
+ selectNone: "Deseleccionar todos",
2475
+ selectedCount: "{count, plural, one {# seleccionado} other {# seleccionados}}",
2476
+ copy: "Copiar",
2477
+ copyNothing: "Selecciona al menos un bloque para copiar.",
2478
+ selectDone: "Listo",
1992
2479
  paste: "Pegar {count, plural, one {# bloque} other {# bloques}}",
1993
2480
  pasted: "{count, plural, one {# bloque pegado} other {# bloques pegados}}.",
1994
2481
  copied: "{count, plural, one {# bloque copiado} other {# bloques copiados}}. P\xE9galos en cualquier p\xE1gina de este sitio.",
@@ -2051,7 +2538,120 @@ var es_default = {
2051
2538
  historyMax: "Instant\xE1neas por documento (m\xE1ximo)",
2052
2539
  historyEventDays: "Conservar la actividad (d\xEDas)",
2053
2540
  historyRetentionHelp: "Una tarea nocturna vac\xEDa las instant\xE1neas m\xE1s antiguas que esto o por encima del m\xE1ximo por documento (se conservan las m\xE1s recientes) y elimina la actividad m\xE1s antigua que su l\xEDmite. Nunca elimina archivos multimedia.",
2054
- historyInvalid: "N\xFAmeros enteros: de 1 a 3650 d\xEDas (la actividad se conserva al menos tanto como las instant\xE1neas) y de 1 a 1000 instant\xE1neas."
2541
+ historyInvalid: "N\xFAmeros enteros: de 1 a 3650 d\xEDas (la actividad se conserva al menos tanto como las instant\xE1neas) y de 1 a 1000 instant\xE1neas.",
2542
+ fieldHelp: "M\xE1s informaci\xF3n",
2543
+ paneTitle: "Barra de la vista previa de p\xE1gina",
2544
+ paneHelp: "Los controles marcados aparecen en la barra de la vista previa de p\xE1gina, en este orden. Estado y Guardar/Publicar van juntos a la derecha; los desmarcados se ocultan.",
2545
+ "toolbar.modes": "Modo de edici\xF3n",
2546
+ "toolbar.history": "Deshacer y rehacer",
2547
+ "toolbar.devices": "Men\xFA de ancho de p\xE1gina",
2548
+ "toolbar.status": "Estado del documento",
2549
+ "toolbar.actions": "Guardar y Publicar",
2550
+ paneDevices: "Anchos de p\xE1gina",
2551
+ paneDevicesHelp: "Opciones del men\xFA de ancho, en orden; la primera se usa hasta que el editor elija otra. Anchos personalizados: de 240 a 3840 px.",
2552
+ paneAddWidth: "A\xF1adir ancho",
2553
+ paneWidthLabel: "Nombre",
2554
+ paneWidth: "Ancho (px)",
2555
+ paneRemoveWidth: "Quitar ancho",
2556
+ paneInvalid: "Mant\xE9n de 1 a 8 anchos, sin repetir; un ancho personalizado necesita nombre (hasta 24 caracteres, sin < ni >) y un n\xFAmero entero de 240 a 3840.",
2557
+ paneTypeOverride: "Barra de vista previa propia para {name}",
2558
+ add: "A\xF1adir bloque",
2559
+ openAll: "Abrir todos los bloques",
2560
+ closeAll: "Cerrar todos los bloques",
2561
+ 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.",
2562
+ previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
2563
+ selectMode: "Seleccionar bloques para copiar",
2564
+ copySelected: "Copiar seleccionados ({count})",
2565
+ trashDays: "Conservar documentos eliminados (d\xEDas)",
2566
+ trashDaysHelp: "Los documentos eliminados quedan en la papelera ese n\xFAmero de d\xEDas (fijado al eliminar cada uno); despu\xE9s la tarea nocturna los borra.",
2567
+ "historyActions.purge": "Eliminado definitivamente",
2568
+ contentMenu: "Actividad y papelera",
2569
+ contentTitle: "Actividad del contenido y papelera",
2570
+ contentSubtitle: "Cambios hechos a trav\xE9s de Strapi (admin, API, plugins) en los tipos de contenido que cubre el historial de versiones.",
2571
+ contentOff: "El historial de versiones est\xE1 desactivado: no se registra ni se env\xEDa a la papelera nada nuevo. Act\xEDvalo en Configuraci\xF3n, Blockscene.",
2572
+ contentLoading: "Cargando\u2026",
2573
+ contentNone: "\u2014",
2574
+ contentUntitled: "(sin t\xEDtulo)",
2575
+ contentGone: "ya no existe",
2576
+ contentOpen: "Abrir",
2577
+ contentPrevious: "Anterior",
2578
+ contentNext: "Siguiente",
2579
+ contentPage: "P\xE1gina {page} de {pages}, {total} en total",
2580
+ contentClear: "Borrar filtros",
2581
+ activityTab: "Actividad",
2582
+ activityPerson: "Persona",
2583
+ activityAnyone: "Cualquiera",
2584
+ activityType: "Tipo de contenido",
2585
+ activityAnyType: "Todos los tipos de contenido",
2586
+ activityAction: "Acci\xF3n",
2587
+ activityAnyAction: "Todas las acciones",
2588
+ activityFrom: "Desde",
2589
+ activityTo: "Hasta",
2590
+ activitySearch: "El t\xEDtulo contiene",
2591
+ activitySearchButton: "Buscar",
2592
+ activityWhen: "Cu\xE1ndo",
2593
+ activityDocument: "Documento",
2594
+ activityWho: "Qui\xE9n",
2595
+ activityWhat: "Qu\xE9",
2596
+ activityEmpty: "Ninguna actividad coincide con estos filtros.",
2597
+ activityFailed: "No se pudo cargar la actividad.",
2598
+ activityRestoredFrom: "Recuperado de la papelera",
2599
+ trashTab: "Papelera",
2600
+ trashShowRestored: "Mostrar entradas restauradas",
2601
+ trashLocales: "Idiomas",
2602
+ trashDeletedBy: "Eliminado por",
2603
+ trashDeletedAt: "Eliminado",
2604
+ trashExpires: "Borrado definitivo",
2605
+ trashExpiresIn: "en {days} d\xEDas",
2606
+ trashExpiresToday: "esta noche",
2607
+ trashRestoredAs: "Restaurado",
2608
+ trashEmpty: "La papelera est\xE1 vac\xEDa.",
2609
+ trashFailed: "No se pudo cargar la papelera.",
2610
+ trashPreview: "Vista previa",
2611
+ trashRestore: "Restaurar",
2612
+ trashDelete: "Eliminar definitivamente",
2613
+ trashDeleteTitle: "Eliminar definitivamente",
2614
+ trashDeleteConfirm: "\xBFEliminar \xAB{title}\xBB de la papelera definitivamente? Despu\xE9s no se podr\xE1 restaurar. Los archivos multimedia no se borran.",
2615
+ trashDeleted: "Eliminado definitivamente.",
2616
+ trashDeleteFailed: "No se pudo eliminar.",
2617
+ trashDraft: "borrador",
2618
+ trashPublished: "publicado",
2619
+ trashFields: "Campos",
2620
+ trashBlocks: "Bloques",
2621
+ trashItems: "{count} elemento(s)",
2622
+ trashIncoming: "Se guardaron {count} v\xEDnculo(s) desde otros documentos o bloques.",
2623
+ trashClose: "Cerrar",
2624
+ restoreTitle: "Restaurar \xAB{title}\xBB",
2625
+ restoreChecking: "Comprobando lo que har\xEDa la restauraci\xF3n\u2026",
2626
+ restoreIntro: "El documento vuelve como borrador, con el contenido del borrador: rev\xEDsalo y vuelve a publicarlo.",
2627
+ restoreNew: "Se crea un documento nuevo (Strapi no reutiliza el id original).",
2628
+ restoreInto: "Los idiomas vuelven al documento que ya existe.",
2629
+ restoreLocales: "Idiomas restaurados: {locales}",
2630
+ restoreBlocked: "No se puede restaurar tal como est\xE1 (no se escribe nada):",
2631
+ restoreWarnings: "Se restaura con estas diferencias:",
2632
+ restoreConfirm: "Restaurar como borrador",
2633
+ restoreCancel: "Cancelar",
2634
+ restoreDone: "Restaurado como borrador.",
2635
+ restoreAlready: "Esta entrada ya se restaur\xF3.",
2636
+ restoreFailed: "La restauraci\xF3n fall\xF3: no se escribi\xF3 nada.",
2637
+ restoreOpen: "Abrir el documento restaurado",
2638
+ "report.typeGone": "El tipo de contenido ya no existe.",
2639
+ "report.localeExists": "El documento vuelve a tener el idioma {locale}.",
2640
+ "report.unique": "\xAB{value}\xBB ya se usa en {field} ({locale}) en otro documento.",
2641
+ "report.singleExists": "Este tipo \xFAnico vuelve a tener un documento.",
2642
+ "report.nothing": "No hay nada que restaurar: ninguno de sus idiomas sigue configurado.",
2643
+ "report.restored": "Ya restaurado.",
2644
+ "report.published": "Exist\xEDa una versi\xF3n publicada ({locales}): queda guardada en la entrada de la papelera; lo que vuelve es el borrador.",
2645
+ "report.localeRemoved": "El idioma {locale} ya no est\xE1 configurado: se omite.",
2646
+ "report.required": "Campos obligatorios vac\xEDos ({locale}): {fields}. Compl\xE9talos antes de publicar.",
2647
+ "report.fieldsRemoved": "Campos que el esquema ya no tiene, omitidos ({locale}): {fields}.",
2648
+ "report.media": "{count} archivo(s) multimedia ya no existen, quedan vac\xEDos ({locale}).",
2649
+ "report.relations": "{count} documento(s) relacionados ya no existen, omitidos ({locale}).",
2650
+ "report.blocks": "{count} bloque(s) cuyo componente la zona ya no permite, omitidos ({locale}).",
2651
+ "report.incoming": "V\xEDnculos desde otros documentos y bloques: {reconnect} repuestos, {gone} cuyo due\xF1o ya no existe, {replaced} cuyo due\xF1o ahora apunta a otro, {published} desde versiones publicadas (vuelven cuando esos documentos se publiquen de nuevo).",
2652
+ groupCollapse: "Contraer el grupo {label}",
2653
+ groupExpand: "Expandir el grupo {label}",
2654
+ groupBlocks: "{count, plural, one {# bloque} other {# bloques}}"
2055
2655
  };
2056
2656
 
2057
2657
  // admin/translations/de.json
@@ -2059,7 +2659,6 @@ var de_default = {
2059
2659
  title: "Blockscene",
2060
2660
  settings: "Galerie",
2061
2661
  gallery: "Blockgalerie",
2062
- add: "Block hinzuf\xFCgen",
2063
2662
  search: "Bl\xF6cke suchen",
2064
2663
  clear: "Suche l\xF6schen",
2065
2664
  empty: "Keine Bl\xF6cke gefunden.",
@@ -2069,8 +2668,9 @@ var de_default = {
2069
2668
  failed: "Der Katalog konnte nicht geladen werden. Schlie\xDFen und erneut versuchen.",
2070
2669
  insertFailed: "Diese Komponente konnte nicht erstellt werden. Verwenden Sie die native Auswahl und melden Sie ihr Schema.",
2071
2670
  example: "Bilder sind Beispiele; das Aussehen h\xE4ngt von Ihrem Frontend ab.",
2072
- openAll: "Alle Bl\xF6cke \xF6ffnen",
2073
- closeAll: "Alle Bl\xF6cke schlie\xDFen",
2671
+ expandAll: "Alle aufklappen",
2672
+ collapseAll: "Alle zuklappen",
2673
+ moreActions: "Weitere Aktionen",
2074
2674
  settingsTitle: "Blockscene",
2075
2675
  settingsIntro: "Galerie-Vorschaubilder, Wireframe-Palette und Editor-Einstellungen. \xC4nderungen gelten beim n\xE4chsten \xD6ffnen der Galerie; kein Rebuild n\xF6tig.",
2076
2676
  palette: "Wireframe-Palette",
@@ -2098,8 +2698,9 @@ var de_default = {
2098
2698
  editor: "Editor-Einstellungen",
2099
2699
  enabled: "Blockscene aktiv",
2100
2700
  enabledHelp: "Aus schaltet das ganze Plugin sofort ab, ohne Neustart: jede Bearbeitungsansicht ist wieder nativ und die Gruppenpr\xFCfung beim Ver\xF6ffentlichen stoppt. F\xFCr den Fall, dass in Produktion etwas schiefgeht.",
2101
- showOpenAll: "\u201EAlle Bl\xF6cke \xF6ffnen\u201C anzeigen",
2102
- showCloseAll: "\u201EAlle Bl\xF6cke schlie\xDFen\u201C anzeigen",
2701
+ showOpenAll: "\u201EAlle aufklappen\u201C anzeigen",
2702
+ showCloseAll: "\u201EAlle zuklappen\u201C anzeigen",
2703
+ toggleHelp: "Die Zonenleiste zeigt einen einzigen Button: Sind beide Optionen an, klappt er auf, solange ein Block zugeklappt ist, sonst klappt er alle zu; ist nur eine an, bietet er nur diese Aktion.",
2103
2704
  showRowThumbnails: "Blockvorschaubilder in den Zeilen anzeigen",
2104
2705
  initialState: "Anfangszustand der Akkordeons",
2105
2706
  "states.closed": "Alle geschlossen",
@@ -2108,6 +2709,7 @@ var de_default = {
2108
2709
  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.",
2109
2710
  previewUrl: "Basis-URL der Vorschauroute",
2110
2711
  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).",
2712
+ previewUrlEmpty: "Keine Vorschau-URL gesetzt: Redakteure erhalten die Modi Felder + Seite und Visueller Editor nur bei Inhaltstypen, f\xFCr die Strapis native Vorschau konfiguriert ist. Sonst wird das Modusmen\xFC nicht angezeigt.",
2111
2713
  previewMode: "Anf\xE4nglicher Vorschaumodus",
2112
2714
  "modes.form": "Felder",
2113
2715
  "modes.split": "Felder + Seite",
@@ -2126,8 +2728,6 @@ var de_default = {
2126
2728
  resize: "Vorschaubereich anpassen",
2127
2729
  resizeHint: "Ziehen zum \xC4ndern der Gr\xF6\xDFe; Doppelklick setzt auf die H\xE4lfte zur\xFCck",
2128
2730
  scrollToHovered: "Zum hervorgehobenen Block scrollen",
2129
- 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.",
2130
- previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
2131
2731
  previewFailed: "Die Vorschau hat innerhalb von 15 s nicht geantwortet. L\xE4dt das Frontend noch, erscheint sie von selbst; das Formular bleibt benutzbar.",
2132
2732
  previewLoading: "Vorschau wird geladen\u2026",
2133
2733
  retry: "Erneut versuchen",
@@ -2272,8 +2872,13 @@ var de_default = {
2272
2872
  confirmDelete: "Block {name} l\xF6schen?",
2273
2873
  confirmDeleteMarker: "Dies ist eine Gruppenmarkierung: Nur die Markierung wird entfernt, nicht die Bl\xF6cke der Gruppe, und die Gruppe bleibt unausgeglichen, bis sie korrigiert ist.",
2274
2874
  delete: "L\xF6schen",
2275
- selectMode: "Bl\xF6cke zum Kopieren ausw\xE4hlen",
2276
- copySelected: "Auswahl kopieren ({count})",
2875
+ selectBlocks: "Bl\xF6cke ausw\xE4hlen",
2876
+ selectAll: "Alle ausw\xE4hlen",
2877
+ selectNone: "Auswahl aufheben",
2878
+ selectedCount: "{count} ausgew\xE4hlt",
2879
+ copy: "Kopieren",
2880
+ copyNothing: "W\xE4hlen Sie mindestens einen Block zum Kopieren aus.",
2881
+ selectDone: "Fertig",
2277
2882
  paste: "{count, plural, one {# Block} other {# Bl\xF6cke}} einf\xFCgen",
2278
2883
  pasted: "{count, plural, one {# Block eingef\xFCgt} other {# Bl\xF6cke eingef\xFCgt}}.",
2279
2884
  copied: "{count, plural, one {# Block kopiert} other {# Bl\xF6cke kopiert}}. Auf jeder Seite dieser Website einf\xFCgbar.",
@@ -2336,7 +2941,120 @@ var de_default = {
2336
2941
  historyMax: "Snapshots pro Dokument (Maximum)",
2337
2942
  historyEventDays: "Aktivit\xE4t aufbewahren (Tage)",
2338
2943
  historyRetentionHelp: "Ein n\xE4chtlicher Job leert Snapshots, die \xE4lter sind oder das Maximum pro Dokument \xFCberschreiten (die neuesten bleiben), und l\xF6scht Aktivit\xE4t, die \xE4lter als ihr Limit ist. Mediendateien l\xF6scht er nie.",
2339
- historyInvalid: "Ganze Zahlen: 1 bis 3650 Tage (die Aktivit\xE4t mindestens so lange wie die Snapshots) und 1 bis 1000 Snapshots."
2944
+ historyInvalid: "Ganze Zahlen: 1 bis 3650 Tage (die Aktivit\xE4t mindestens so lange wie die Snapshots) und 1 bis 1000 Snapshots.",
2945
+ fieldHelp: "Weitere Informationen",
2946
+ paneTitle: "Werkzeugleiste der Seitenvorschau",
2947
+ paneHelp: "Markierte Bedienelemente erscheinen in dieser Reihenfolge in der Werkzeugleiste der Seitenvorschau. Status und Speichern/Ver\xF6ffentlichen bleiben rechts zusammen; nicht markierte sind ausgeblendet.",
2948
+ "toolbar.modes": "Bearbeitungsmodus",
2949
+ "toolbar.history": "R\xFCckg\xE4ngig und Wiederholen",
2950
+ "toolbar.devices": "Men\xFC der Seitenbreite",
2951
+ "toolbar.status": "Dokumentstatus",
2952
+ "toolbar.actions": "Speichern und Ver\xF6ffentlichen",
2953
+ paneDevices: "Seitenbreiten",
2954
+ paneDevicesHelp: "Eintr\xE4ge des Breitenmen\xFCs in Reihenfolge; der erste gilt, bis eine Redaktion einen anderen w\xE4hlt. Eigene Breiten: 240 bis 3840 px.",
2955
+ paneAddWidth: "Breite hinzuf\xFCgen",
2956
+ paneWidthLabel: "Bezeichnung",
2957
+ paneWidth: "Breite (px)",
2958
+ paneRemoveWidth: "Breite entfernen",
2959
+ paneInvalid: "1 bis 8 Breiten, keine doppelt; eine eigene Breite braucht eine Bezeichnung (bis 24 Zeichen, ohne < oder >) und eine ganze Zahl von 240 bis 3840.",
2960
+ paneTypeOverride: "Eigene Vorschau-Werkzeugleiste f\xFCr {name}",
2961
+ add: "Block hinzuf\xFCgen",
2962
+ openAll: "Alle Bl\xF6cke \xF6ffnen",
2963
+ closeAll: "Alle Bl\xF6cke schlie\xDFen",
2964
+ 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.",
2965
+ previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
2966
+ selectMode: "Bl\xF6cke zum Kopieren ausw\xE4hlen",
2967
+ copySelected: "Auswahl kopieren ({count})",
2968
+ trashDays: "Gel\xF6schte Dokumente aufbewahren (Tage)",
2969
+ trashDaysHelp: "Gel\xF6schte Dokumente bleiben so viele Tage im Papierkorb (beim L\xF6schen jeweils festgelegt), danach entfernt sie der n\xE4chtliche Job.",
2970
+ "historyActions.purge": "Endg\xFCltig gel\xF6scht",
2971
+ contentMenu: "Aktivit\xE4t und Papierkorb",
2972
+ contentTitle: "Inhaltsaktivit\xE4t und Papierkorb",
2973
+ contentSubtitle: "\xC4nderungen \xFCber Strapi (Admin, API, Plugins) an den Inhaltstypen, die der Versionsverlauf abdeckt.",
2974
+ contentOff: "Der Versionsverlauf ist aus: Neues wird weder aufgezeichnet noch in den Papierkorb gelegt. Aktivieren unter Einstellungen, Blockscene.",
2975
+ contentLoading: "Wird geladen\u2026",
2976
+ contentNone: "\u2014",
2977
+ contentUntitled: "(ohne Titel)",
2978
+ contentGone: "existiert nicht mehr",
2979
+ contentOpen: "\xD6ffnen",
2980
+ contentPrevious: "Zur\xFCck",
2981
+ contentNext: "Weiter",
2982
+ contentPage: "Seite {page} von {pages}, insgesamt {total}",
2983
+ contentClear: "Filter zur\xFCcksetzen",
2984
+ activityTab: "Aktivit\xE4t",
2985
+ activityPerson: "Person",
2986
+ activityAnyone: "Alle",
2987
+ activityType: "Inhaltstyp",
2988
+ activityAnyType: "Alle Inhaltstypen",
2989
+ activityAction: "Aktion",
2990
+ activityAnyAction: "Alle Aktionen",
2991
+ activityFrom: "Von",
2992
+ activityTo: "Bis",
2993
+ activitySearch: "Titel enth\xE4lt",
2994
+ activitySearchButton: "Suchen",
2995
+ activityWhen: "Wann",
2996
+ activityDocument: "Dokument",
2997
+ activityWho: "Wer",
2998
+ activityWhat: "Was",
2999
+ activityEmpty: "Keine Aktivit\xE4t passt zu diesen Filtern.",
3000
+ activityFailed: "Die Aktivit\xE4t konnte nicht geladen werden.",
3001
+ activityRestoredFrom: "Aus dem Papierkorb zur\xFCck",
3002
+ trashTab: "Papierkorb",
3003
+ trashShowRestored: "Wiederhergestellte Eintr\xE4ge anzeigen",
3004
+ trashLocales: "Sprachen",
3005
+ trashDeletedBy: "Gel\xF6scht von",
3006
+ trashDeletedAt: "Gel\xF6scht",
3007
+ trashExpires: "Endg\xFCltig gel\xF6scht",
3008
+ trashExpiresIn: "in {days} Tagen",
3009
+ trashExpiresToday: "heute Nacht",
3010
+ trashRestoredAs: "Wiederhergestellt",
3011
+ trashEmpty: "Der Papierkorb ist leer.",
3012
+ trashFailed: "Der Papierkorb konnte nicht geladen werden.",
3013
+ trashPreview: "Vorschau",
3014
+ trashRestore: "Wiederherstellen",
3015
+ trashDelete: "Endg\xFCltig l\xF6schen",
3016
+ trashDeleteTitle: "Endg\xFCltig l\xF6schen",
3017
+ trashDeleteConfirm: "\u201E{title}\u201C endg\xFCltig aus dem Papierkorb l\xF6schen? Danach l\xE4sst es sich nicht wiederherstellen. Mediendateien werden nicht gel\xF6scht.",
3018
+ trashDeleted: "Endg\xFCltig gel\xF6scht.",
3019
+ trashDeleteFailed: "Es konnte nicht gel\xF6scht werden.",
3020
+ trashDraft: "Entwurf",
3021
+ trashPublished: "ver\xF6ffentlicht",
3022
+ trashFields: "Felder",
3023
+ trashBlocks: "Bl\xF6cke",
3024
+ trashItems: "{count} Element(e)",
3025
+ trashIncoming: "{count} Verkn\xFCpfung(en) aus anderen Dokumenten oder Bl\xF6cken wurden gesichert.",
3026
+ trashClose: "Schlie\xDFen",
3027
+ restoreTitle: "\u201E{title}\u201C wiederherstellen",
3028
+ restoreChecking: "Es wird gepr\xFCft, was die Wiederherstellung tun w\xFCrde\u2026",
3029
+ restoreIntro: "Das Dokument kommt als Entwurf zur\xFCck, mit dem Inhalt des Entwurfs: pr\xFCfen und dann erneut ver\xF6ffentlichen.",
3030
+ restoreNew: "Ein neues Dokument wird angelegt (Strapi verwendet die urspr\xFCngliche ID nicht wieder).",
3031
+ restoreInto: "Die Sprachen kommen in das bestehende Dokument zur\xFCck.",
3032
+ restoreLocales: "Wiederhergestellte Sprachen: {locales}",
3033
+ restoreBlocked: "So kann es nicht wiederhergestellt werden (nichts wird geschrieben):",
3034
+ restoreWarnings: "Es wird mit diesen Abweichungen wiederhergestellt:",
3035
+ restoreConfirm: "Als Entwurf wiederherstellen",
3036
+ restoreCancel: "Abbrechen",
3037
+ restoreDone: "Als Entwurf wiederhergestellt.",
3038
+ restoreAlready: "Dieser Eintrag wurde bereits wiederhergestellt.",
3039
+ restoreFailed: "Die Wiederherstellung ist fehlgeschlagen: nichts wurde geschrieben.",
3040
+ restoreOpen: "Wiederhergestelltes Dokument \xF6ffnen",
3041
+ "report.typeGone": "Der Inhaltstyp existiert nicht mehr.",
3042
+ "report.localeExists": "Das Dokument hat die Sprache {locale} wieder.",
3043
+ "report.unique": "\u201E{value}\u201C wird in {field} ({locale}) bereits von einem anderen Dokument verwendet.",
3044
+ "report.singleExists": "Dieser Single Type hat wieder ein Dokument.",
3045
+ "report.nothing": "Nichts wiederherzustellen: keine seiner Sprachen ist noch konfiguriert.",
3046
+ "report.restored": "Bereits wiederhergestellt.",
3047
+ "report.published": "Es gab eine ver\xF6ffentlichte Version ({locales}): sie bleibt im Papierkorbeintrag, zur\xFCck kommt der Entwurf.",
3048
+ "report.localeRemoved": "Die Sprache {locale} ist nicht mehr konfiguriert: \xFCbersprungen.",
3049
+ "report.required": "Leere Pflichtfelder ({locale}): {fields}. Vor dem Ver\xF6ffentlichen ausf\xFCllen.",
3050
+ "report.fieldsRemoved": "Felder, die das Schema nicht mehr hat, ausgelassen ({locale}): {fields}.",
3051
+ "report.media": "{count} Mediendatei(en) existieren nicht mehr, leer gelassen ({locale}).",
3052
+ "report.relations": "{count} verkn\xFCpfte(s) Dokument(e) existieren nicht mehr, ausgelassen ({locale}).",
3053
+ "report.blocks": "{count} Block/Bl\xF6cke, deren Komponente die Zone nicht mehr erlaubt, ausgelassen ({locale}).",
3054
+ "report.incoming": "Verkn\xFCpfungen aus anderen Dokumenten und Bl\xF6cken: {reconnect} wiederhergestellt, {gone} ohne existierenden Besitzer, {replaced} deren Besitzer jetzt woandershin zeigt, {published} aus ver\xF6ffentlichten Versionen (sie kommen zur\xFCck, wenn diese Dokumente erneut ver\xF6ffentlicht werden).",
3055
+ groupCollapse: "Gruppe {label} einklappen",
3056
+ groupExpand: "Gruppe {label} ausklappen",
3057
+ groupBlocks: "{count, plural, one {# Block} other {# Bl\xF6cke}}"
2340
3058
  };
2341
3059
 
2342
3060
  // admin/translations/it.json
@@ -2344,7 +3062,6 @@ var it_default = {
2344
3062
  title: "Blockscene",
2345
3063
  settings: "Galleria",
2346
3064
  gallery: "Galleria dei blocchi",
2347
- add: "Aggiungi blocco",
2348
3065
  search: "Cerca blocchi",
2349
3066
  clear: "Cancella ricerca",
2350
3067
  empty: "Nessun blocco trovato.",
@@ -2354,8 +3071,9 @@ var it_default = {
2354
3071
  failed: "Impossibile caricare il catalogo. Chiudi e riprova.",
2355
3072
  insertFailed: "Impossibile creare questo componente. Usa il selettore nativo e segnala il suo schema.",
2356
3073
  example: "Le immagini sono esempi; l'aspetto dipende dal tuo frontend.",
2357
- openAll: "Apri tutti i blocchi",
2358
- closeAll: "Chiudi tutti i blocchi",
3074
+ expandAll: "Espandi tutto",
3075
+ collapseAll: "Comprimi tutto",
3076
+ moreActions: "Altre azioni",
2359
3077
  settingsTitle: "Blockscene",
2360
3078
  settingsIntro: "Miniature della galleria, palette dei wireframe e preferenze dell'editor. Le modifiche valgono alla prossima apertura della galleria; non serve alcun rebuild.",
2361
3079
  palette: "Palette dei wireframe",
@@ -2383,8 +3101,9 @@ var it_default = {
2383
3101
  editor: "Preferenze dell'editor",
2384
3102
  enabled: "Blockscene attivo",
2385
3103
  enabledHelp: "Disattivato, l'intero plugin si ferma subito, senza riavvio: ogni vista di modifica torna nativa e il controllo dei gruppi alla pubblicazione si ferma. Da usare se qualcosa va storto in produzione.",
2386
- showOpenAll: 'Mostra "Apri tutti i blocchi"',
2387
- showCloseAll: 'Mostra "Chiudi tutti i blocchi"',
3104
+ showOpenAll: 'Mostra "Espandi tutto"',
3105
+ showCloseAll: 'Mostra "Comprimi tutto"',
3106
+ toggleHelp: "La barra della zona mostra un solo pulsante: con entrambe le opzioni attive espande finch\xE9 c'\xE8 un blocco compresso, altrimenti li comprime tutti; con una sola, offre solo quell'azione.",
2388
3107
  showRowThumbnails: "Mostra le miniature dei blocchi nelle righe",
2389
3108
  initialState: "Stato iniziale delle fisarmoniche",
2390
3109
  "states.closed": "Tutte chiuse",
@@ -2393,6 +3112,7 @@ var it_default = {
2393
3112
  rememberHelp: "Solo i pulsanti espliciti apri tutti / chiudi tutti aggiornano la memoria, per utente e browser. Aprire un singolo blocco non la cambia.",
2394
3113
  previewUrl: "URL di base della route di anteprima",
2395
3114
  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).",
3115
+ previewUrlEmpty: "Nessun URL di anteprima impostato: gli editor hanno le modalit\xE0 Campi + pagina ed Editor visivo solo sui tipi di contenuto con l'anteprima nativa di Strapi configurata. Altrove il menu delle modalit\xE0 non compare.",
2396
3116
  previewMode: "Modalit\xE0 iniziale dell'anteprima",
2397
3117
  "modes.form": "Campi",
2398
3118
  "modes.split": "Campi + pagina",
@@ -2411,8 +3131,6 @@ var it_default = {
2411
3131
  resize: "Ridimensiona il pannello di anteprima",
2412
3132
  resizeHint: "Trascina per ridimensionare; doppio clic per tornare a met\xE0",
2413
3133
  scrollToHovered: "Scorri fino al blocco evidenziato",
2414
- 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.",
2415
- previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
2416
3134
  previewFailed: "L'anteprima non ha risposto entro 15 s. Se il frontend sta ancora caricando, comparir\xE0 da sola; il modulo resta utilizzabile.",
2417
3135
  previewLoading: "Caricamento dell'anteprima\u2026",
2418
3136
  retry: "Riprova",
@@ -2557,8 +3275,13 @@ var it_default = {
2557
3275
  confirmDelete: "Eliminare il blocco {name}?",
2558
3276
  confirmDeleteMarker: "\xC8 un marcatore di gruppo: viene rimosso solo il marcatore, non i blocchi del gruppo, e il gruppo resta sbilanciato finch\xE9 non viene corretto.",
2559
3277
  delete: "Elimina",
2560
- selectMode: "Seleziona i blocchi da copiare",
2561
- copySelected: "Copia selezionati ({count})",
3278
+ selectBlocks: "Seleziona blocchi",
3279
+ selectAll: "Seleziona tutti",
3280
+ selectNone: "Deseleziona tutti",
3281
+ selectedCount: "{count, plural, one {# selezionato} other {# selezionati}}",
3282
+ copy: "Copia",
3283
+ copyNothing: "Seleziona almeno un blocco da copiare.",
3284
+ selectDone: "Fine",
2562
3285
  paste: "Incolla {count, plural, one {# blocco} other {# blocchi}}",
2563
3286
  pasted: "{count, plural, one {# blocco incollato} other {# blocchi incollati}}.",
2564
3287
  copied: "{count, plural, one {# blocco copiato} other {# blocchi copiati}}. Incollali in qualsiasi pagina di questo sito.",
@@ -2621,7 +3344,120 @@ var it_default = {
2621
3344
  historyMax: "Istantanee per documento (massimo)",
2622
3345
  historyEventDays: "Conserva l'attivit\xE0 (giorni)",
2623
3346
  historyRetentionHelp: "Un'attivit\xE0 notturna svuota le istantanee pi\xF9 vecchie di cos\xEC o oltre il massimo per documento (le pi\xF9 recenti restano) ed elimina l'attivit\xE0 pi\xF9 vecchia del suo limite. Non elimina mai file multimediali.",
2624
- historyInvalid: "Numeri interi: da 1 a 3650 giorni (l'attivit\xE0 conservata almeno quanto le istantanee) e da 1 a 1000 istantanee."
3347
+ historyInvalid: "Numeri interi: da 1 a 3650 giorni (l'attivit\xE0 conservata almeno quanto le istantanee) e da 1 a 1000 istantanee.",
3348
+ fieldHelp: "Maggiori informazioni",
3349
+ paneTitle: "Barra dell'anteprima pagina",
3350
+ paneHelp: "I controlli selezionati compaiono nella barra dell'anteprima pagina, in questo ordine. Stato e Salva/Pubblica restano insieme a destra; quelli non selezionati sono nascosti.",
3351
+ "toolbar.modes": "Modalit\xE0 di modifica",
3352
+ "toolbar.history": "Annulla e ripeti",
3353
+ "toolbar.devices": "Menu della larghezza pagina",
3354
+ "toolbar.status": "Stato del documento",
3355
+ "toolbar.actions": "Salva e Pubblica",
3356
+ paneDevices: "Larghezze della pagina",
3357
+ paneDevicesHelp: "Voci del menu della larghezza, in ordine; la prima vale finch\xE9 l'editor non ne sceglie un'altra. Larghezze personalizzate: da 240 a 3840 px.",
3358
+ paneAddWidth: "Aggiungi larghezza",
3359
+ paneWidthLabel: "Etichetta",
3360
+ paneWidth: "Larghezza (px)",
3361
+ paneRemoveWidth: "Rimuovi larghezza",
3362
+ paneInvalid: "Tieni da 1 a 8 larghezze, senza ripetizioni; una larghezza personalizzata richiede un'etichetta (fino a 24 caratteri, senza < o >) e un numero intero da 240 a 3840.",
3363
+ paneTypeOverride: "Barra dell'anteprima propria per {name}",
3364
+ add: "Aggiungi blocco",
3365
+ openAll: "Apri tutti i blocchi",
3366
+ closeAll: "Chiudi tutti i blocchi",
3367
+ 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.",
3368
+ previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
3369
+ selectMode: "Seleziona i blocchi da copiare",
3370
+ copySelected: "Copia selezionati ({count})",
3371
+ trashDays: "Conserva i documenti eliminati (giorni)",
3372
+ trashDaysHelp: "I documenti eliminati restano nel cestino per questo numero di giorni (fissato quando ognuno viene eliminato), poi l'attivit\xE0 notturna li cancella.",
3373
+ "historyActions.purge": "Eliminato definitivamente",
3374
+ contentMenu: "Attivit\xE0 e cestino",
3375
+ contentTitle: "Attivit\xE0 dei contenuti e cestino",
3376
+ contentSubtitle: "Modifiche fatte tramite Strapi (admin, API, plugin) ai tipi di contenuto coperti dalla cronologia delle versioni.",
3377
+ contentOff: "La cronologia delle versioni \xE8 disattivata: niente di nuovo viene registrato o messo nel cestino. Attivala in Impostazioni, Blockscene.",
3378
+ contentLoading: "Caricamento\u2026",
3379
+ contentNone: "\u2014",
3380
+ contentUntitled: "(senza titolo)",
3381
+ contentGone: "non esiste pi\xF9",
3382
+ contentOpen: "Apri",
3383
+ contentPrevious: "Precedente",
3384
+ contentNext: "Successiva",
3385
+ contentPage: "Pagina {page} di {pages}, {total} in totale",
3386
+ contentClear: "Azzera i filtri",
3387
+ activityTab: "Attivit\xE0",
3388
+ activityPerson: "Persona",
3389
+ activityAnyone: "Chiunque",
3390
+ activityType: "Tipo di contenuto",
3391
+ activityAnyType: "Tutti i tipi di contenuto",
3392
+ activityAction: "Azione",
3393
+ activityAnyAction: "Tutte le azioni",
3394
+ activityFrom: "Dal",
3395
+ activityTo: "Al",
3396
+ activitySearch: "Il titolo contiene",
3397
+ activitySearchButton: "Cerca",
3398
+ activityWhen: "Quando",
3399
+ activityDocument: "Documento",
3400
+ activityWho: "Chi",
3401
+ activityWhat: "Cosa",
3402
+ activityEmpty: "Nessuna attivit\xE0 corrisponde a questi filtri.",
3403
+ activityFailed: "Non \xE8 stato possibile caricare l'attivit\xE0.",
3404
+ activityRestoredFrom: "Recuperato dal cestino",
3405
+ trashTab: "Cestino",
3406
+ trashShowRestored: "Mostra le voci ripristinate",
3407
+ trashLocales: "Lingue",
3408
+ trashDeletedBy: "Eliminato da",
3409
+ trashDeletedAt: "Eliminato",
3410
+ trashExpires: "Eliminazione definitiva",
3411
+ trashExpiresIn: "tra {days} giorni",
3412
+ trashExpiresToday: "stanotte",
3413
+ trashRestoredAs: "Ripristinato",
3414
+ trashEmpty: "Il cestino \xE8 vuoto.",
3415
+ trashFailed: "Non \xE8 stato possibile caricare il cestino.",
3416
+ trashPreview: "Anteprima",
3417
+ trashRestore: "Ripristina",
3418
+ trashDelete: "Elimina definitivamente",
3419
+ trashDeleteTitle: "Elimina definitivamente",
3420
+ trashDeleteConfirm: "Eliminare definitivamente \u201C{title}\u201D dal cestino? Dopo non potr\xE0 pi\xF9 essere ripristinato. I file multimediali non vengono eliminati.",
3421
+ trashDeleted: "Eliminato definitivamente.",
3422
+ trashDeleteFailed: "Non \xE8 stato possibile eliminarlo.",
3423
+ trashDraft: "bozza",
3424
+ trashPublished: "pubblicato",
3425
+ trashFields: "Campi",
3426
+ trashBlocks: "Blocchi",
3427
+ trashItems: "{count} elemento/i",
3428
+ trashIncoming: "Sono stati conservati {count} collegamento/i da altri documenti o blocchi.",
3429
+ trashClose: "Chiudi",
3430
+ restoreTitle: "Ripristina \u201C{title}\u201D",
3431
+ restoreChecking: "Verifica di cosa farebbe il ripristino\u2026",
3432
+ restoreIntro: "Il documento torna come bozza, con il contenuto della bozza: controllalo e poi pubblicalo di nuovo.",
3433
+ restoreNew: "Viene creato un nuovo documento (Strapi non riutilizza l'id originale).",
3434
+ restoreInto: "Le lingue tornano nel documento esistente.",
3435
+ restoreLocales: "Lingue ripristinate: {locales}",
3436
+ restoreBlocked: "Non pu\xF2 essere ripristinato cos\xEC com'\xE8 (non viene scritto nulla):",
3437
+ restoreWarnings: "Viene ripristinato con queste differenze:",
3438
+ restoreConfirm: "Ripristina come bozza",
3439
+ restoreCancel: "Annulla",
3440
+ restoreDone: "Ripristinato come bozza.",
3441
+ restoreAlready: "Questa voce \xE8 gi\xE0 stata ripristinata.",
3442
+ restoreFailed: "Il ripristino non \xE8 riuscito: non \xE8 stato scritto nulla.",
3443
+ restoreOpen: "Apri il documento ripristinato",
3444
+ "report.typeGone": "Il tipo di contenuto non esiste pi\xF9.",
3445
+ "report.localeExists": "Il documento ha di nuovo la lingua {locale}.",
3446
+ "report.unique": "\u201C{value}\u201D \xE8 gi\xE0 usato in {field} ({locale}) da un altro documento.",
3447
+ "report.singleExists": "Questo single type ha di nuovo un documento.",
3448
+ "report.nothing": "Niente da ripristinare: nessuna delle sue lingue \xE8 ancora configurata.",
3449
+ "report.restored": "Gi\xE0 ripristinato.",
3450
+ "report.published": "Esisteva una versione pubblicata ({locales}): resta nella voce del cestino, torna la bozza.",
3451
+ "report.localeRemoved": "La lingua {locale} non \xE8 pi\xF9 configurata: saltata.",
3452
+ "report.required": "Campi obbligatori vuoti ({locale}): {fields}. Compilali prima di pubblicare.",
3453
+ "report.fieldsRemoved": "Campi che lo schema non ha pi\xF9, esclusi ({locale}): {fields}.",
3454
+ "report.media": "{count} file multimediale/i non esistono pi\xF9, lasciati vuoti ({locale}).",
3455
+ "report.relations": "{count} documento/i collegati non esistono pi\xF9, esclusi ({locale}).",
3456
+ "report.blocks": "{count} blocco/i il cui componente la zona non consente pi\xF9, esclusi ({locale}).",
3457
+ "report.incoming": "Collegamenti da altri documenti e blocchi: {reconnect} rimessi al loro posto, {gone} il cui proprietario non esiste pi\xF9, {replaced} il cui proprietario ora punta altrove, {published} da versioni pubblicate (tornano quando quei documenti vengono ripubblicati).",
3458
+ groupCollapse: "Comprimi il gruppo {label}",
3459
+ groupExpand: "Espandi il gruppo {label}",
3460
+ groupBlocks: "{count, plural, one {# blocco} other {# blocchi}}"
2625
3461
  };
2626
3462
 
2627
3463
  // admin/translations/nl.json
@@ -2629,7 +3465,6 @@ var nl_default = {
2629
3465
  title: "Blockscene",
2630
3466
  settings: "Galerij",
2631
3467
  gallery: "Blokkengalerij",
2632
- add: "Blok toevoegen",
2633
3468
  search: "Blokken zoeken",
2634
3469
  clear: "Zoekopdracht wissen",
2635
3470
  empty: "Geen blokken gevonden.",
@@ -2639,8 +3474,9 @@ var nl_default = {
2639
3474
  failed: "De catalogus kon niet worden geladen. Sluit en probeer opnieuw.",
2640
3475
  insertFailed: "Dit component kon niet worden aangemaakt. Gebruik de native kiezer en meld het schema.",
2641
3476
  example: "Afbeeldingen zijn voorbeelden; het uiterlijk hangt af van uw frontend.",
2642
- openAll: "Alle blokken openen",
2643
- closeAll: "Alle blokken sluiten",
3477
+ expandAll: "Alles uitklappen",
3478
+ collapseAll: "Alles inklappen",
3479
+ moreActions: "Meer acties",
2644
3480
  settingsTitle: "Blockscene",
2645
3481
  settingsIntro: "Galerijminiaturen, wireframe-palet en editorvoorkeuren. Wijzigingen gelden bij de volgende opening van de galerij; geen rebuild nodig.",
2646
3482
  palette: "Wireframe-palet",
@@ -2668,8 +3504,9 @@ var nl_default = {
2668
3504
  editor: "Editorvoorkeuren",
2669
3505
  enabled: "Blockscene aan",
2670
3506
  enabledHelp: "Uit zet de hele plugin meteen uit, zonder herstart: elke bewerkweergave is weer native en de groepscontrole bij publiceren stopt. Gebruik dit als er in productie iets misgaat.",
2671
- showOpenAll: '"Alle blokken openen" tonen',
2672
- showCloseAll: '"Alle blokken sluiten" tonen',
3507
+ showOpenAll: '"Alles uitklappen" tonen',
3508
+ showCloseAll: '"Alles inklappen" tonen',
3509
+ toggleHelp: "De zonebalk toont \xE9\xE9n knop: staan beide opties aan, dan klapt hij uit zolang er een blok ingeklapt is en klapt hij anders alles in; staat er maar \xE9\xE9n aan, dan biedt hij alleen die actie.",
2673
3510
  showRowThumbnails: "Blokminiaturen in de rijen tonen",
2674
3511
  initialState: "Beginstand van de accordeons",
2675
3512
  "states.closed": "Alle gesloten",
@@ -2678,6 +3515,7 @@ var nl_default = {
2678
3515
  rememberHelp: "Alleen de expliciete knoppen alles openen / alles sluiten werken het geheugen bij, per gebruiker en browser. E\xE9n blok openen verandert niets.",
2679
3516
  previewUrl: "Basis-URL van de voorbeeldroute",
2680
3517
  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).",
3518
+ previewUrlEmpty: "Geen preview-URL ingesteld: redacteuren krijgen de modi Velden + pagina en Visuele editor alleen bij inhoudstypes waarvoor de native Preview van Strapi is ingesteld. Elders verschijnt het modusmenu niet.",
2681
3519
  previewMode: "Beginmodus van het voorbeeld",
2682
3520
  "modes.form": "Velden",
2683
3521
  "modes.split": "Velden + pagina",
@@ -2696,8 +3534,6 @@ var nl_default = {
2696
3534
  resize: "Voorbeeldpaneel aanpassen",
2697
3535
  resizeHint: "Sleep om te wijzigen; dubbelklik zet terug op de helft",
2698
3536
  scrollToHovered: "Naar het gemarkeerde blok scrollen",
2699
- 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.",
2700
- previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
2701
3537
  previewFailed: "Het voorbeeld antwoordde niet binnen 15 s. Als de frontend nog laadt, verschijnt het vanzelf; het formulier blijft bruikbaar.",
2702
3538
  previewLoading: "Voorbeeld laden\u2026",
2703
3539
  retry: "Opnieuw proberen",
@@ -2842,8 +3678,13 @@ var nl_default = {
2842
3678
  confirmDelete: "Blok {name} verwijderen?",
2843
3679
  confirmDeleteMarker: "Dit is een groepsmarkering: alleen de markering wordt verwijderd, niet de blokken in de groep, en de groep blijft onevenwichtig tot hij hersteld is.",
2844
3680
  delete: "Verwijderen",
2845
- selectMode: "Blokken selecteren om te kopi\xEBren",
2846
- copySelected: "Selectie kopi\xEBren ({count})",
3681
+ selectBlocks: "Blokken selecteren",
3682
+ selectAll: "Alles selecteren",
3683
+ selectNone: "Niets selecteren",
3684
+ selectedCount: "{count} geselecteerd",
3685
+ copy: "Kopi\xEBren",
3686
+ copyNothing: "Selecteer minstens \xE9\xE9n blok om te kopi\xEBren.",
3687
+ selectDone: "Klaar",
2847
3688
  paste: "{count, plural, one {# blok} other {# blokken}} plakken",
2848
3689
  pasted: "{count, plural, one {# blok geplakt} other {# blokken geplakt}}.",
2849
3690
  copied: "{count, plural, one {# blok gekopieerd} other {# blokken gekopieerd}}. Plak ze op elke pagina van deze site.",
@@ -2906,7 +3747,120 @@ var nl_default = {
2906
3747
  historyMax: "Momentopnamen per document (maximum)",
2907
3748
  historyEventDays: "Activiteit bewaren (dagen)",
2908
3749
  historyRetentionHelp: "Een nachtelijke taak leegt momentopnamen die ouder zijn of boven het maximum per document uitkomen (de nieuwste blijven) en verwijdert activiteit die ouder is dan de limiet. Mediabestanden worden nooit verwijderd.",
2909
- historyInvalid: "Gehele getallen: 1 tot 3650 dagen (de activiteit minstens zo lang bewaard als de momentopnamen) en 1 tot 1000 momentopnamen."
3750
+ historyInvalid: "Gehele getallen: 1 tot 3650 dagen (de activiteit minstens zo lang bewaard als de momentopnamen) en 1 tot 1000 momentopnamen.",
3751
+ fieldHelp: "Meer informatie",
3752
+ paneTitle: "Werkbalk van het paginavoorbeeld",
3753
+ paneHelp: "Aangevinkte bedieningselementen staan in deze volgorde op de werkbalk van het paginavoorbeeld. Status en Opslaan/Publiceren blijven samen rechts; niet aangevinkte zijn verborgen.",
3754
+ "toolbar.modes": "Bewerkmodus",
3755
+ "toolbar.history": "Ongedaan maken en opnieuw",
3756
+ "toolbar.devices": "Menu paginabreedte",
3757
+ "toolbar.status": "Documentstatus",
3758
+ "toolbar.actions": "Opslaan en Publiceren",
3759
+ paneDevices: "Paginabreedtes",
3760
+ paneDevicesHelp: "Opties van het breedtemenu, op volgorde; de eerste geldt tot een redacteur een andere kiest. Eigen breedtes: 240 tot 3840 px.",
3761
+ paneAddWidth: "Breedte toevoegen",
3762
+ paneWidthLabel: "Label",
3763
+ paneWidth: "Breedte (px)",
3764
+ paneRemoveWidth: "Breedte verwijderen",
3765
+ paneInvalid: "Houd 1 tot 8 breedtes, geen dubbele; een eigen breedte heeft een label nodig (tot 24 tekens, zonder < of >) en een geheel getal van 240 tot 3840.",
3766
+ paneTypeOverride: "Eigen werkbalk van het paginavoorbeeld voor {name}",
3767
+ add: "Blok toevoegen",
3768
+ openAll: "Alle blokken openen",
3769
+ closeAll: "Alle blokken sluiten",
3770
+ 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.",
3771
+ previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
3772
+ selectMode: "Blokken selecteren om te kopi\xEBren",
3773
+ copySelected: "Selectie kopi\xEBren ({count})",
3774
+ trashDays: "Verwijderde documenten bewaren (dagen)",
3775
+ trashDaysHelp: "Verwijderde documenten blijven zoveel dagen in de prullenbak (vastgelegd bij elke verwijdering), daarna wist de nachtelijke taak ze.",
3776
+ "historyActions.purge": "Definitief verwijderd",
3777
+ contentMenu: "Activiteit en prullenbak",
3778
+ contentTitle: "Contentactiviteit en prullenbak",
3779
+ contentSubtitle: "Wijzigingen via Strapi (admin, API, plugins) aan de contenttypes die de versiegeschiedenis dekt.",
3780
+ contentOff: "Versiegeschiedenis staat uit: er wordt niets nieuws vastgelegd of in de prullenbak gezet. Zet hem aan in Instellingen, Blockscene.",
3781
+ contentLoading: "Laden\u2026",
3782
+ contentNone: "\u2014",
3783
+ contentUntitled: "(zonder titel)",
3784
+ contentGone: "bestaat niet meer",
3785
+ contentOpen: "Openen",
3786
+ contentPrevious: "Vorige",
3787
+ contentNext: "Volgende",
3788
+ contentPage: "Pagina {page} van {pages}, {total} in totaal",
3789
+ contentClear: "Filters wissen",
3790
+ activityTab: "Activiteit",
3791
+ activityPerson: "Persoon",
3792
+ activityAnyone: "Iedereen",
3793
+ activityType: "Contenttype",
3794
+ activityAnyType: "Alle contenttypes",
3795
+ activityAction: "Actie",
3796
+ activityAnyAction: "Alle acties",
3797
+ activityFrom: "Van",
3798
+ activityTo: "Tot",
3799
+ activitySearch: "Titel bevat",
3800
+ activitySearchButton: "Zoeken",
3801
+ activityWhen: "Wanneer",
3802
+ activityDocument: "Document",
3803
+ activityWho: "Wie",
3804
+ activityWhat: "Wat",
3805
+ activityEmpty: "Geen activiteit past bij deze filters.",
3806
+ activityFailed: "De activiteit kon niet worden geladen.",
3807
+ activityRestoredFrom: "Terug uit de prullenbak",
3808
+ trashTab: "Prullenbak",
3809
+ trashShowRestored: "Herstelde items tonen",
3810
+ trashLocales: "Talen",
3811
+ trashDeletedBy: "Verwijderd door",
3812
+ trashDeletedAt: "Verwijderd",
3813
+ trashExpires: "Definitief verwijderd",
3814
+ trashExpiresIn: "over {days} dagen",
3815
+ trashExpiresToday: "vannacht",
3816
+ trashRestoredAs: "Hersteld",
3817
+ trashEmpty: "De prullenbak is leeg.",
3818
+ trashFailed: "De prullenbak kon niet worden geladen.",
3819
+ trashPreview: "Voorbeeld",
3820
+ trashRestore: "Herstellen",
3821
+ trashDelete: "Definitief verwijderen",
3822
+ trashDeleteTitle: "Definitief verwijderen",
3823
+ trashDeleteConfirm: "\u201C{title}\u201D definitief uit de prullenbak verwijderen? Daarna kan het niet meer worden hersteld. Mediabestanden worden niet verwijderd.",
3824
+ trashDeleted: "Definitief verwijderd.",
3825
+ trashDeleteFailed: "Het kon niet worden verwijderd.",
3826
+ trashDraft: "concept",
3827
+ trashPublished: "gepubliceerd",
3828
+ trashFields: "Velden",
3829
+ trashBlocks: "Blokken",
3830
+ trashItems: "{count} item(s)",
3831
+ trashIncoming: "{count} koppeling(en) vanuit andere documenten of blokken zijn bewaard.",
3832
+ trashClose: "Sluiten",
3833
+ restoreTitle: "\u201C{title}\u201D herstellen",
3834
+ restoreChecking: "Controleren wat herstellen zou doen\u2026",
3835
+ restoreIntro: "Het document komt terug als concept, met de inhoud van het concept: controleer het en publiceer het opnieuw.",
3836
+ restoreNew: "Er wordt een nieuw document gemaakt (Strapi hergebruikt de oorspronkelijke id niet).",
3837
+ restoreInto: "De talen komen terug in het bestaande document.",
3838
+ restoreLocales: "Herstelde talen: {locales}",
3839
+ restoreBlocked: "Zo kan het niet worden hersteld (er wordt niets geschreven):",
3840
+ restoreWarnings: "Het wordt hersteld met deze verschillen:",
3841
+ restoreConfirm: "Herstellen als concept",
3842
+ restoreCancel: "Annuleren",
3843
+ restoreDone: "Hersteld als concept.",
3844
+ restoreAlready: "Dit item is al hersteld.",
3845
+ restoreFailed: "Herstellen is mislukt: er is niets geschreven.",
3846
+ restoreOpen: "Het herstelde document openen",
3847
+ "report.typeGone": "Het contenttype bestaat niet meer.",
3848
+ "report.localeExists": "Het document heeft de taal {locale} weer.",
3849
+ "report.unique": "\u201C{value}\u201D wordt al gebruikt in {field} ({locale}) door een ander document.",
3850
+ "report.singleExists": "Dit single type heeft weer een document.",
3851
+ "report.nothing": "Niets te herstellen: geen van de talen is nog ingesteld.",
3852
+ "report.restored": "Al hersteld.",
3853
+ "report.published": "Er bestond een gepubliceerde versie ({locales}): die blijft in het prullenbakitem, het concept komt terug.",
3854
+ "report.localeRemoved": "De taal {locale} is niet meer ingesteld: overgeslagen.",
3855
+ "report.required": "Lege verplichte velden ({locale}): {fields}. Vul ze in voor het publiceren.",
3856
+ "report.fieldsRemoved": "Velden die het schema niet meer heeft, weggelaten ({locale}): {fields}.",
3857
+ "report.media": "{count} mediabestand(en) bestaan niet meer, leeg gelaten ({locale}).",
3858
+ "report.relations": "{count} gekoppelde document(en) bestaan niet meer, weggelaten ({locale}).",
3859
+ "report.blocks": "{count} blok(ken) waarvan de zone het component niet meer toestaat, weggelaten ({locale}).",
3860
+ "report.incoming": "Koppelingen vanuit andere documenten en blokken: {reconnect} teruggezet, {gone} waarvan de eigenaar niet meer bestaat, {replaced} waarvan de eigenaar nu ergens anders naar wijst, {published} vanuit gepubliceerde versies (die komen terug wanneer die documenten opnieuw worden gepubliceerd).",
3861
+ groupCollapse: "Groep {label} inklappen",
3862
+ groupExpand: "Groep {label} uitklappen",
3863
+ groupBlocks: "{count, plural, one {# blok} other {# blokken}}"
2910
3864
  };
2911
3865
 
2912
3866
  // admin/messages.ts
@@ -3078,11 +4032,10 @@ function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
3078
4032
  ] });
3079
4033
  }
3080
4034
 
3081
- // admin/RowActions.tsx
4035
+ // admin/GroupRows.tsx
3082
4036
  var React3 = __toESM(require("react"));
3083
4037
  var import_react_dom2 = require("react-dom");
3084
4038
  var import_styled_components2 = __toESM(require("styled-components"));
3085
- var import_design_system = require("@strapi/design-system");
3086
4039
 
3087
4040
  // admin/rows.mjs
3088
4041
  var import_fractional_indexing2 = require("fractional-indexing");
@@ -3126,9 +4079,9 @@ function integerKeys(rows, n) {
3126
4079
  const max = Math.max(-1, ...rows.map((row) => Number(row?.__temp_key__)).filter(Number.isFinite));
3127
4080
  return Array.from({ length: n }, (_, i) => max + 1 + i);
3128
4081
  }
3129
- var insertRows = (rows, at, items, keys) => [
4082
+ var insertRows = (rows, at, items2, keys) => [
3130
4083
  ...rows.slice(0, at),
3131
- ...items.map((item, i) => ({ ...item, __temp_key__: keys[i] })),
4084
+ ...items2.map((item, i) => ({ ...item, __temp_key__: keys[i] })),
3132
4085
  ...rows.slice(at)
3133
4086
  ];
3134
4087
  function setHidden(rows, index, groups, name, value) {
@@ -3162,6 +4115,85 @@ function pasteProblem(clip, zone, rows, components, groups) {
3162
4115
  if (groups && (0, import_groups2.validateGroups)(clip.rows, groups).length) return { code: "unbalanced" };
3163
4116
  return null;
3164
4117
  }
4118
+ function groupOutline(rows, groups) {
4119
+ const out = rows.map(() => ({ depth: 0, kind: "block", parents: [] }));
4120
+ if (!groups) return out;
4121
+ const stack = [];
4122
+ rows.forEach((row, i) => {
4123
+ const parents = stack.map((s) => s.index);
4124
+ const top = stack[stack.length - 1];
4125
+ if (top && (0, import_groups2.isClose)(row, groups) && row.__component === top.close) {
4126
+ stack.pop();
4127
+ out[top.index].end = i;
4128
+ out[top.index].count = out.slice(top.index + 1, i).filter((r) => r.kind !== "close").length;
4129
+ out[i] = { depth: parents.length, kind: "close", parents };
4130
+ return;
4131
+ }
4132
+ const open = (0, import_groups2.isOpener)(row, groups);
4133
+ out[i] = { depth: parents.length, kind: open ? "open" : "block", parents };
4134
+ if (open) stack.push({ index: i, close: groups[row.__component] });
4135
+ });
4136
+ return out;
4137
+ }
4138
+ function movedRow(prev, next, actor) {
4139
+ const n = prev.length;
4140
+ if (n !== next.length || n < 2) return null;
4141
+ const k = prev.map(import_groups2.blockKey), m = next.map(import_groups2.blockKey);
4142
+ let i = 0;
4143
+ while (i < n && k[i] === m[i]) i++;
4144
+ if (i === n) return null;
4145
+ let j = n - 1;
4146
+ while (k[j] === m[j]) j--;
4147
+ const same = (a, b) => (0, import_groups2.blockKey)(a) === (0, import_groups2.blockKey)(b) || a?.id == null && b?.id == null && a?.__component === b?.__component;
4148
+ const shifted = (from, to, by) => {
4149
+ for (let x = from; x <= to; x++) if (m[x] !== k[x + by]) return false;
4150
+ return true;
4151
+ };
4152
+ const down = same(prev[i], next[j]) && shifted(i, j - 1, 1);
4153
+ const up = same(prev[j], next[i]) && shifted(i + 1, j, -1);
4154
+ if (down && up) return actor === k[i] ? { from: i, to: j } : actor === k[j] ? { from: j, to: i } : null;
4155
+ return down ? { from: i, to: j } : up ? { from: j, to: i } : null;
4156
+ }
4157
+ function keepGroupsTogether(prev, next, groups, actor) {
4158
+ if (!groups) return null;
4159
+ const move = movedRow(prev, next, actor);
4160
+ if (!move || !(0, import_groups2.isOpener)(prev[move.from], groups)) return null;
4161
+ const start = move.from, end = groupOutline(prev, groups)[start].end;
4162
+ if (end == null) return null;
4163
+ const members = new Set(prev.slice(start + 1, end + 1).map(import_groups2.blockKey));
4164
+ const at = move.to;
4165
+ if (at > 0 && members.has((0, import_groups2.blockKey)(next[at - 1]))) {
4166
+ if (end + 1 >= prev.length) return prev.slice();
4167
+ const rest = [...prev.slice(0, start), ...prev.slice(end + 1)];
4168
+ return [...rest.slice(0, start + 1), ...prev.slice(start, end + 1), ...rest.slice(start + 1)];
4169
+ }
4170
+ const others = next.filter((row) => !members.has((0, import_groups2.blockKey)(row)));
4171
+ const o = others.indexOf(next[at]);
4172
+ return [...others.slice(0, o + 1), ...next.filter((row) => members.has((0, import_groups2.blockKey)(row))), ...others.slice(o + 1)];
4173
+ }
4174
+ function errorRows(errors, zone) {
4175
+ const out = /* @__PURE__ */ new Set();
4176
+ const nested = errors?.[zone];
4177
+ if (nested && typeof nested === "object") {
4178
+ for (const [key, value] of Object.entries(nested)) if (value && /^\d+$/.test(key)) out.add(Number(key));
4179
+ }
4180
+ for (const key of Object.keys(errors || {})) {
4181
+ const hit = key.startsWith(`${zone}.`) && /^(\d+)(\.|$)/.exec(key.slice(zone.length + 1));
4182
+ if (hit) out.add(Number(hit[1]));
4183
+ }
4184
+ return [...out];
4185
+ }
4186
+
4187
+ // admin/history.mjs
4188
+ var drag = { id: 0, open: false, until: 0 };
4189
+ var startDrag = () => {
4190
+ drag.id++;
4191
+ drag.open = true;
4192
+ };
4193
+ var endDrag = (now = Date.now(), settle = 400) => {
4194
+ drag.open = false;
4195
+ drag.until = now + settle;
4196
+ };
3165
4197
 
3166
4198
  // admin/icons.tsx
3167
4199
  var import_styled_components = __toESM(require("styled-components"));
@@ -3208,8 +4240,11 @@ var PATHS = {
3208
4240
  duplicate: "M8 8h12v12H8zM4 16V4h12",
3209
4241
  clipboard: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2",
3210
4242
  paste: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2M12 10v7M9 14l3 3 3-3",
3211
- select: "M4 4h16v16H4zM8 12l3 3 5-6"
4243
+ select: "M4 4h16v16H4zM8 12l3 3 5-6",
4244
+ // Zone bar: the "…" menu.
4245
+ more: "M5 11.2a.8.8 0 1 0 0 1.6.8.8 0 0 0 0-1.6zM12 11.2a.8.8 0 1 0 0 1.6.8.8 0 0 0 0-1.6zM19 11.2a.8.8 0 1 0 0 1.6.8.8 0 0 0 0-1.6z"
3212
4246
  };
4247
+ var ICON_NAMES = Object.keys(PATHS);
3213
4248
  function Icon({ name, size = 18, filled }) {
3214
4249
  const d = PATHS[name];
3215
4250
  if (!d) return null;
@@ -3226,9 +4261,234 @@ var ToolButton = import_styled_components.default.button`
3226
4261
  `;
3227
4262
  var Tool = ({ icon, label, active, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolButton, { type: "button", "aria-label": label, title: label, $active: active, ...active !== void 0 ? { "aria-pressed": active } : {}, ...rest, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { name: icon }) });
3228
4263
 
3229
- // admin/RowActions.tsx
4264
+ // admin/GroupRows.tsx
3230
4265
  var import_jsx_runtime4 = require("react/jsx-runtime");
4266
+ var DEPTH = "data-blockscene-depth";
4267
+ var KIND = "data-blockscene-group";
4268
+ var FOLD = "data-blockscene-fold";
4269
+ var COUNT = "data-blockscene-fold-count";
4270
+ var STEP = "2.4rem";
4271
+ var folded = /* @__PURE__ */ new Set();
4272
+ var set = (el, name, value) => {
4273
+ if (value === null) el.hasAttribute(name) && el.removeAttribute(name);
4274
+ else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
4275
+ };
4276
+ var items = (list) => [...list.querySelectorAll(":scope > li")];
4277
+ var Fold = import_styled_components2.default.span`
4278
+ display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 28px; height: 28px; margin-left: 8px;
4279
+ border-radius: 4px; cursor: pointer; color: ${({ theme }) => theme.colors.primary600};
4280
+ background: ${({ theme, $open }) => $open ? "transparent" : theme.colors.primary100};
4281
+ &:hover { background: ${({ theme }) => theme.colors.primary100}; }
4282
+ &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: -2px; }
4283
+ > span { display: inline-flex; transition: transform 120ms; transform: rotate(${({ $open }) => $open ? "0" : "-90deg"}); }
4284
+ `;
4285
+ var Count = import_styled_components2.default.span`
4286
+ margin-right: 4px; padding: 1px 6px; border-radius: 3px; font-size: 11px; font-weight: 600; line-height: 16px; white-space: nowrap;
4287
+ color: ${({ theme }) => theme.colors.primary700}; background: ${({ theme }) => theme.colors.primary100};
4288
+ `;
4289
+ function GroupRows({ zones, form, groups, docKey, labelOf }) {
4290
+ const t = useMessages();
4291
+ const theme = (0, import_styled_components2.useTheme)();
4292
+ const on = Boolean(groups && form);
4293
+ const [anchors, setAnchors] = React3.useState([]);
4294
+ const [, settle] = React3.useReducer((n) => n + 1, 0);
4295
+ const settled = React3.useRef(/* @__PURE__ */ new Map());
4296
+ const actor = React3.useRef(null);
4297
+ const landed = React3.useRef(null);
4298
+ const dragging = React3.useRef(false);
4299
+ const previewed = React3.useRef(false);
4300
+ const end = React3.useRef(() => {
4301
+ if (!dragging.current) return;
4302
+ dragging.current = previewed.current = false;
4303
+ endDrag();
4304
+ settle();
4305
+ }).current;
4306
+ const latest = React3.useRef({ zones, form, docKey, labelOf });
4307
+ latest.current = { zones, form, docKey, labelOf };
4308
+ React3.useEffect(() => settled.current.clear(), [docKey]);
4309
+ React3.useEffect(() => {
4310
+ if (!on || dragging.current) return;
4311
+ for (const zone of zones) {
4312
+ const rows = form.rows(zone.name);
4313
+ const prev = settled.current.get(zone.name);
4314
+ settled.current.set(zone.name, rows);
4315
+ if (!prev || prev === rows) continue;
4316
+ const move = movedRow(prev, rows, actor.current);
4317
+ if (move) landed.current = { zone: zone.name, key: blockKey(rows[move.to]) };
4318
+ const next = keepGroupsTogether(prev, rows, groups, actor.current);
4319
+ if (next) {
4320
+ settled.current.set(zone.name, next);
4321
+ form.setRows(zone.name, next);
4322
+ }
4323
+ }
4324
+ });
4325
+ React3.useEffect(() => {
4326
+ if (!on) return;
4327
+ const rowKey = (target) => {
4328
+ const li = target?.closest?.("ol[aria-describedby] > li");
4329
+ if (!li) return null;
4330
+ for (const zone of latest.current.zones) {
4331
+ const list2 = findZoneList(zone.label);
4332
+ if (li.parentElement === list2) return blockKey(latest.current.form.rows(zone.name)[items(list2).indexOf(li)]) || null;
4333
+ }
4334
+ return null;
4335
+ };
4336
+ const act = (event) => {
4337
+ actor.current = event.metaKey || event.ctrlKey || event.altKey ? null : rowKey(event.target);
4338
+ };
4339
+ const start = (event) => {
4340
+ if (!rowKey(event.target)) return;
4341
+ dragging.current = true;
4342
+ startDrag();
4343
+ };
4344
+ const ends = ["drop", "dragend", "mousemove", "pointerdown", "keydown"];
4345
+ document.addEventListener("pointerdown", act, true);
4346
+ document.addEventListener("keydown", act, true);
4347
+ document.addEventListener("dragstart", start, true);
4348
+ for (const type of ends) window.addEventListener(type, end, true);
4349
+ return () => {
4350
+ document.removeEventListener("pointerdown", act, true);
4351
+ document.removeEventListener("keydown", act, true);
4352
+ document.removeEventListener("dragstart", start, true);
4353
+ for (const type of ends) window.removeEventListener(type, end, true);
4354
+ };
4355
+ }, [on]);
4356
+ const sync = React3.useRef(() => {
4357
+ });
4358
+ sync.current = () => {
4359
+ const { zones: zones2, form: form2, docKey: docKey2, labelOf: labelOf2 } = latest.current;
4360
+ if (dragging.current) {
4361
+ const placeholder = zones2.some((zone) => {
4362
+ const list2 = findZoneList(zone.label);
4363
+ return list2 && items(list2).some((li) => !li.querySelector("button[aria-expanded]"));
4364
+ });
4365
+ if (placeholder) previewed.current = true;
4366
+ else if (previewed.current) end();
4367
+ return;
4368
+ }
4369
+ const next = [];
4370
+ const seen = /* @__PURE__ */ new Set();
4371
+ if (on)
4372
+ for (const zone of zones2) {
4373
+ const list2 = zone.count ? findZoneList(zone.label) : null;
4374
+ const rows = form2.rows(zone.name);
4375
+ const lis = list2 ? items(list2) : [];
4376
+ if (!list2 || lis.length !== rows.length) continue;
4377
+ const outline = groupOutline(rows, groups);
4378
+ const idOf = (i) => `${docKey2}|${zone.name}|${blockKey(rows[i])}`;
4379
+ const unfold = [...form2.errorRows?.(zone.name) || []];
4380
+ if (landed.current?.zone === zone.name) unfold.push(rows.findIndex((row) => blockKey(row) === landed.current?.key));
4381
+ for (const index of unfold) for (const p of outline[index]?.parents || []) folded.delete(idOf(p));
4382
+ const isFolded = (i) => outline[i].end != null && folded.has(idOf(i));
4383
+ lis.forEach((li, i) => {
4384
+ const o = outline[i];
4385
+ seen.add(li);
4386
+ set(li, DEPTH, o.depth ? String(o.depth) : null);
4387
+ if (o.depth) li.style.setProperty("--bs-depth", String(o.depth));
4388
+ set(li, KIND, o.kind === "block" ? null : o.kind);
4389
+ set(li, FOLDED, o.parents.some(isFolded) ? "" : null);
4390
+ const toggle = li.querySelector("button[aria-expanded]");
4391
+ if (o.kind !== "open" || o.end == null || !toggle?.parentElement) return;
4392
+ let el = toggle.parentElement.querySelector(`:scope > [${FOLD}]`);
4393
+ if (!el) {
4394
+ el = document.createElement("span");
4395
+ el.setAttribute(FOLD, "");
4396
+ el.style.cssText = "display:inline-flex;align-items:center";
4397
+ toggle.parentElement.insertBefore(el, toggle);
4398
+ }
4399
+ const actions = toggle.nextElementSibling;
4400
+ let countEl = actions?.querySelector(`:scope > [${COUNT}]`) || null;
4401
+ if (actions && !countEl) {
4402
+ countEl = document.createElement("span");
4403
+ countEl.setAttribute(COUNT, "");
4404
+ countEl.style.cssText = "display:inline-flex;align-items:center";
4405
+ actions.insertBefore(countEl, actions.firstChild);
4406
+ }
4407
+ next.push({ el, countEl, zone: zone.name, index: i, id: idOf(i), count: o.count || 0, open: !isFolded(i), label: labelOf2(rows[i]) });
4408
+ });
4409
+ }
4410
+ landed.current = null;
4411
+ for (const li of document.querySelectorAll(`li[${DEPTH}], li[${KIND}], li[${FOLDED}]`))
4412
+ if (!seen.has(li)) for (const name of [DEPTH, KIND, FOLDED]) li.removeAttribute(name);
4413
+ for (const el of document.querySelectorAll(`[${FOLD}], [${COUNT}]`)) if (!next.some((a) => a.el === el || a.countEl === el)) el.remove();
4414
+ setAnchors(
4415
+ (prev) => prev.length === next.length && prev.every((a, i) => ["el", "countEl", "id", "index", "count", "open", "label"].every((k) => a[k] === next[i][k])) ? prev : next
4416
+ );
4417
+ };
4418
+ React3.useEffect(() => {
4419
+ sync.current();
4420
+ });
4421
+ React3.useEffect(() => {
4422
+ let frame2 = 0;
4423
+ const observer = new MutationObserver(() => {
4424
+ if (!frame2) frame2 = requestAnimationFrame(() => {
4425
+ frame2 = 0;
4426
+ sync.current();
4427
+ });
4428
+ });
4429
+ observer.observe(document.body, { childList: true, subtree: true });
4430
+ return () => {
4431
+ observer.disconnect();
4432
+ cancelAnimationFrame(frame2);
4433
+ for (const el of document.querySelectorAll(`[${FOLD}], [${COUNT}]`)) el.remove();
4434
+ for (const li of document.querySelectorAll(`li[${DEPTH}], li[${KIND}], li[${FOLDED}]`)) for (const name of [DEPTH, KIND, FOLDED]) li.removeAttribute(name);
4435
+ };
4436
+ }, []);
4437
+ if (!on) return null;
4438
+ const flip2 = (id) => {
4439
+ if (folded.has(id)) folded.delete(id);
4440
+ else folded.add(id);
4441
+ sync.current();
4442
+ };
4443
+ const line = theme?.colors?.primary600 || "#4945ff";
4444
+ const list = "ol[aria-describedby] > li";
4445
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
4446
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
4447
+ ${list}[${DEPTH}] { padding-left: calc(var(--bs-depth) * ${STEP}); background: repeating-linear-gradient(to right, ${line} 0 2px, transparent 2px ${STEP}) 1.1rem 0 / calc(var(--bs-depth) * ${STEP}) 100% no-repeat; }
4448
+ ${list}[${FOLDED}] { display: none !important; }
4449
+ ${list}[${KIND}="close"] [data-handler-id] { display: none !important; }
4450
+ ${list}[${KIND}="close"] button[aria-expanded]:first-of-type { min-height: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; opacity: 0.7; }
4451
+ ${list}[${KIND}="close"] button[aria-expanded]:first-of-type + * { padding-top: 0 !important; padding-bottom: 0 !important; }
4452
+ ${list}[${KIND}="close"] button[aria-expanded] [data-blockscene-row-thumb] { display: none; }` }),
4453
+ anchors.map(
4454
+ (a) => (0, import_react_dom2.createPortal)(
4455
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4456
+ Fold,
4457
+ {
4458
+ role: "button",
4459
+ tabIndex: 0,
4460
+ $open: a.open,
4461
+ "aria-expanded": a.open,
4462
+ "data-testid": `group-fold-${a.zone}-${a.index}`,
4463
+ title: t.f(a.open ? "groupCollapse" : "groupExpand", { label: a.label }),
4464
+ "aria-label": t.f(a.open ? "groupCollapse" : "groupExpand", { label: a.label }),
4465
+ onClick: () => flip2(a.id),
4466
+ onKeyDown: (event) => {
4467
+ if (event.key !== "Enter" && event.key !== " ") return;
4468
+ event.preventDefault();
4469
+ flip2(a.id);
4470
+ },
4471
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "chevron", size: 16 }) })
4472
+ }
4473
+ ),
4474
+ a.el,
4475
+ `fold:${a.zone}:${a.index}`
4476
+ )
4477
+ ),
4478
+ anchors.map(
4479
+ (a) => !a.open && a.countEl ? (0, import_react_dom2.createPortal)(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Count, { "data-testid": `group-count-${a.zone}-${a.index}`, children: t.f("groupBlocks", { count: a.count }) }), a.countEl, `count:${a.zone}:${a.index}`) : null
4480
+ )
4481
+ ] });
4482
+ }
4483
+
4484
+ // admin/RowActions.tsx
4485
+ var React4 = __toESM(require("react"));
4486
+ var import_react_dom3 = require("react-dom");
4487
+ var import_styled_components3 = __toESM(require("styled-components"));
4488
+ var import_design_system = require("@strapi/design-system");
4489
+ var import_jsx_runtime5 = require("react/jsx-runtime");
3231
4490
  var ATTR2 = "data-blockscene-row-actions";
4491
+ var SELECT_ATTR = "data-blockscene-row-select";
3232
4492
  var HIDDEN_ATTR = "data-blockscene-hidden";
3233
4493
  var CLIP_EVENT = "blockscene:clipboard";
3234
4494
  var storage = () => {
@@ -3239,8 +4499,8 @@ var storage = () => {
3239
4499
  }
3240
4500
  };
3241
4501
  function useClipboard() {
3242
- const [clip, setClip] = React3.useState(() => readClip(storage()));
3243
- React3.useEffect(() => {
4502
+ const [clip, setClip] = React4.useState(() => readClip(storage()));
4503
+ React4.useEffect(() => {
3244
4504
  const sync = (event) => {
3245
4505
  if (!event?.key || event.key === CLIPBOARD_KEY) setClip(readClip(storage()));
3246
4506
  };
@@ -3275,16 +4535,16 @@ function pasteInto(form, zone, clip, components, groups, t, at) {
3275
4535
  }
3276
4536
  var actionsOf = (toggle) => toggle.nextElementSibling;
3277
4537
  var trashOf = (toggle) => [...actionsOf(toggle)?.querySelectorAll("button") || []].find((b) => !b.closest(`[${ATTR2}]`)) || null;
3278
- function useAnchors2(zones, enabled) {
3279
- const [anchors, setAnchors] = React3.useState([]);
3280
- const latest = React3.useRef(zones);
3281
- latest.current = zones;
3282
- const sync = React3.useRef(() => {
4538
+ function useAnchors2(zones, enabled, selecting) {
4539
+ const [anchors, setAnchors] = React4.useState([]);
4540
+ const latest = React4.useRef({ zones, selecting });
4541
+ latest.current = { zones, selecting };
4542
+ const sync = React4.useRef(() => {
3283
4543
  });
3284
4544
  sync.current = () => {
3285
4545
  const next = [];
3286
4546
  if (enabled)
3287
- for (const zone of latest.current) {
4547
+ for (const zone of latest.current.zones) {
3288
4548
  const list = zone.count ? findZoneList(zone.label) : null;
3289
4549
  if (!list) continue;
3290
4550
  toggles(list).forEach((toggle, index) => {
@@ -3298,18 +4558,29 @@ function useAnchors2(zones, enabled) {
3298
4558
  el.style.cssText = "display:inline-flex;align-items:center";
3299
4559
  holder.parentElement?.insertBefore(el, holder);
3300
4560
  }
3301
- next.push({ el, zone: zone.name, index });
4561
+ let select = null;
4562
+ if (latest.current.selecting === zone.name && toggle.parentElement) {
4563
+ select = toggle.parentElement.querySelector(`:scope > [${SELECT_ATTR}]`);
4564
+ if (!select) {
4565
+ select = document.createElement("span");
4566
+ select.setAttribute(SELECT_ATTR, "");
4567
+ select.style.cssText = "display:inline-flex;align-items:center;padding-left:12px";
4568
+ toggle.parentElement.insertBefore(select, toggle);
4569
+ }
4570
+ }
4571
+ next.push({ el, select, zone: zone.name, index });
3302
4572
  });
3303
4573
  }
3304
- for (const el of document.querySelectorAll(`[${ATTR2}]`)) if (!next.some((a) => a.el === el)) el.remove();
4574
+ for (const attr of [ATTR2, SELECT_ATTR])
4575
+ for (const el of document.querySelectorAll(`[${attr}]`)) if (!next.some((a) => a.el === el || a.select === el)) el.remove();
3305
4576
  setAnchors(
3306
- (prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.zone === next[i].zone && a.index === next[i].index) ? prev : next
4577
+ (prev) => prev.length === next.length && prev.every((a, i) => a.el === next[i].el && a.select === next[i].select && a.zone === next[i].zone && a.index === next[i].index) ? prev : next
3307
4578
  );
3308
4579
  };
3309
- React3.useEffect(() => {
4580
+ React4.useEffect(() => {
3310
4581
  sync.current();
3311
4582
  });
3312
- React3.useEffect(() => {
4583
+ React4.useEffect(() => {
3313
4584
  let frame2 = 0;
3314
4585
  const observer = new MutationObserver(() => {
3315
4586
  if (!frame2) frame2 = requestAnimationFrame(() => {
@@ -3321,7 +4592,7 @@ function useAnchors2(zones, enabled) {
3321
4592
  return () => {
3322
4593
  observer.disconnect();
3323
4594
  cancelAnimationFrame(frame2);
3324
- for (const el of document.querySelectorAll(`[${ATTR2}]`)) el.remove();
4595
+ for (const el of document.querySelectorAll(`[${ATTR2}], [${SELECT_ATTR}]`)) el.remove();
3325
4596
  for (const el of document.querySelectorAll(`[${HIDDEN_ATTR}]`)) el.removeAttribute(HIDDEN_ATTR);
3326
4597
  };
3327
4598
  }, []);
@@ -3330,8 +4601,16 @@ function useAnchors2(zones, enabled) {
3330
4601
  function useRowActions({ zones, components, catalog, form }) {
3331
4602
  const t = useMessages();
3332
4603
  const clip = useClipboard();
3333
- const [selection, setSelection] = React3.useState(null);
3334
- const [busy, setBusy] = React3.useState(false);
4604
+ const [selection, setSelection] = React4.useState(null);
4605
+ const [busy, setBusy] = React4.useState(false);
4606
+ React4.useEffect(() => {
4607
+ if (!selection) return;
4608
+ const onKey = (event) => {
4609
+ if (event.key === "Escape" && !event.defaultPrevented && !document.querySelector('[role="dialog"]')) setSelection(null);
4610
+ };
4611
+ document.addEventListener("keydown", onKey);
4612
+ return () => document.removeEventListener("keydown", onKey);
4613
+ }, [Boolean(selection)]);
3335
4614
  if (!form) return null;
3336
4615
  const editor = catalog?.editor || {};
3337
4616
  const groups = catalog?.groups || null;
@@ -3355,30 +4634,32 @@ function useRowActions({ zones, components, catalog, form }) {
3355
4634
  const key = blockKey(rows[index]);
3356
4635
  const [start, end] = actionRange(rows, index, groups);
3357
4636
  if (rows.length + end - start + 1 > (zone?.max ?? Infinity)) return form.notify("warning", t.zoneFull);
3358
- const items = await form.prepare(rows.slice(start, end + 1));
4637
+ const items2 = await form.prepare(rows.slice(start, end + 1));
3359
4638
  const now = form.rows(zoneName);
3360
4639
  const at = now.findIndex((row) => blockKey(row) === key);
3361
4640
  if (at < 0) return;
3362
4641
  const after = actionRange(now, at, groups)[1] + 1;
3363
- form.setRows(zoneName, insertRows(now, after, items, form.keys(now, after, items.length)));
4642
+ form.setRows(zoneName, insertRows(now, after, items2, form.keys(now, after, items2.length)));
3364
4643
  });
3365
4644
  const copy2 = (zoneName, keys) => run(async () => {
3366
4645
  const rows = form.rows(zoneName);
3367
4646
  const indexes = expandSelection(rows, keys.map((key) => rows.findIndex((row) => blockKey(row) === key)), groups);
3368
4647
  if (!indexes.length) return;
3369
- const items = await form.prepare(indexes.map((i) => rows[i]));
3370
- if (!storeClip({ rows: items, model: form.model, locale: form.locale, zone: zoneName })) return form.notify("warning", t.copyFailed);
4648
+ const items2 = await form.prepare(indexes.map((i) => rows[i]));
4649
+ if (!storeClip({ rows: items2, model: form.model, locale: form.locale, zone: zoneName })) return form.notify("warning", t.copyFailed);
3371
4650
  setSelection(null);
3372
- form.notify("success", t.f("copied", { count: items.length }));
4651
+ form.notify("success", t.f("copied", { count: items2.length }));
3373
4652
  });
3374
4653
  const toggleHidden = (zoneName, index) => {
3375
4654
  const rows = form.rows(zoneName);
3376
4655
  if (hiddenName) form.setRows(zoneName, setHidden(rows, index, groups, hiddenName, rows[index]?.[hiddenName] !== true));
3377
4656
  };
3378
4657
  const paste = (zoneName, at) => pasteInto(form, zoneOf(zoneName), clip, components, groups, t, at);
3379
- return { t, editor, groups, hiddenName, clip, selection, setSelection, busy, form, labelOf, duplicate, copy: copy2, toggleHidden, paste, isMarker: (row) => isGroupMarker(row, groups) };
4658
+ const pastable = (zoneName) => !["empty", "notAllowed"].includes(pasteProblem(clip, zoneOf(zoneName), form.rows(zoneName), components, groups)?.code);
4659
+ const selectable = (zoneName) => form.rows(zoneName).filter((row) => canAct(row, groups)).map((row) => blockKey(row)).filter(Boolean);
4660
+ return { t, editor, groups, hiddenName, clip, selection, setSelection, busy, form, labelOf, duplicate, copy: copy2, toggleHidden, paste, pastable, selectable, isMarker: (row) => isGroupMarker(row, groups) };
3380
4661
  }
3381
- var RowButton = import_styled_components2.default.button`
4662
+ var RowButton = import_styled_components3.default.button`
3382
4663
  display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border: 0;
3383
4664
  border-radius: 4px; cursor: pointer; background: transparent;
3384
4665
  color: ${({ theme, $on }) => $on ? theme.colors.warning600 : theme.colors.neutral500};
@@ -3386,7 +4667,7 @@ var RowButton = import_styled_components2.default.button`
3386
4667
  &:disabled { opacity: 0.4; cursor: default; }
3387
4668
  &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: -2px; }
3388
4669
  `;
3389
- var HiddenBadge = import_styled_components2.default.span`
4670
+ var HiddenBadge = import_styled_components3.default.span`
3390
4671
  margin-right: 4px; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; line-height: 16px;
3391
4672
  text-transform: uppercase; letter-spacing: 0.04em;
3392
4673
  color: ${({ theme }) => theme.colors.warning700}; background: ${({ theme }) => theme.colors.warning100};
@@ -3394,12 +4675,12 @@ var HiddenBadge = import_styled_components2.default.span`
3394
4675
  function RowActions({ zones, actions, Modal: Modal2 }) {
3395
4676
  const a = actions;
3396
4677
  const e = a?.editor || {};
3397
- const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection));
3398
- const [confirm, setConfirm] = React3.useState(null);
3399
- const bypass = React3.useRef(false);
3400
- const latest = React3.useRef({ zones, a });
4678
+ const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection), a?.selection?.zone || null);
4679
+ const [confirm, setConfirm] = React4.useState(null);
4680
+ const bypass = React4.useRef(false);
4681
+ const latest = React4.useRef({ zones, a });
3401
4682
  latest.current = { zones, a };
3402
- React3.useEffect(() => {
4683
+ React4.useEffect(() => {
3403
4684
  if (!a || e.confirmDelete === false) return;
3404
4685
  const onClick = (event) => {
3405
4686
  const button = event.target?.closest?.("button");
@@ -3420,7 +4701,7 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3420
4701
  document.addEventListener("click", onClick, true);
3421
4702
  return () => document.removeEventListener("click", onClick, true);
3422
4703
  }, [Boolean(a), e.confirmDelete]);
3423
- React3.useEffect(() => {
4704
+ React4.useEffect(() => {
3424
4705
  if (!a) return;
3425
4706
  for (const { el, zone, index } of anchors) {
3426
4707
  const li = el.closest("li");
@@ -3441,8 +4722,29 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3441
4722
  bypass.current = false;
3442
4723
  }
3443
4724
  };
3444
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3445
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `li[${HIDDEN_ATTR}] button[aria-expanded] { opacity: 0.5; }` }),
4725
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4726
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("style", { children: `li[${HIDDEN_ATTR}] button[aria-expanded] { opacity: 0.5; }` }),
4727
+ anchors.map(({ select, zone, index }) => {
4728
+ const row = a.form.rows(zone)[index];
4729
+ const key = blockKey(row) || "";
4730
+ if (!select || !row || !canAct(row, a.groups) || a.selection?.zone !== zone) return null;
4731
+ const label = a.labelOf(row);
4732
+ return (0, import_react_dom3.createPortal)(
4733
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4734
+ "input",
4735
+ {
4736
+ type: "checkbox",
4737
+ "aria-label": t.f("selectBlock", { label }),
4738
+ "data-testid": `row-select-${zone}-${index}`,
4739
+ style: { margin: 0, width: 16, height: 16, cursor: "pointer" },
4740
+ checked: a.selection.keys.includes(key),
4741
+ onChange: (event) => a.setSelection({ zone, keys: event.target.checked ? [...a.selection.keys, key] : a.selection.keys.filter((k) => k !== key) })
4742
+ }
4743
+ ),
4744
+ select,
4745
+ `select:${zone}:${index}`
4746
+ );
4747
+ }),
3446
4748
  anchors.map(({ el, zone, index }) => {
3447
4749
  const row = a.form.rows(zone)[index];
3448
4750
  if (!row) return null;
@@ -3450,22 +4752,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3450
4752
  const acts = canAct(row, a.groups);
3451
4753
  const hidden = Boolean(a.hiddenName) && row[a.hiddenName] === true;
3452
4754
  const key = blockKey(row) || "";
3453
- const selecting = a.selection?.zone === zone;
3454
- return (0, import_react_dom2.createPortal)(
3455
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { gap: 0, alignItems: "center", "data-testid": `row-actions-${zone}-${index}`, role: "group", "aria-label": t.f("rowActions", { label }), children: [
3456
- selecting && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3457
- "input",
3458
- {
3459
- type: "checkbox",
3460
- "aria-label": t.f("selectBlock", { label }),
3461
- "data-testid": `row-select-${zone}-${index}`,
3462
- style: { margin: "0 8px", width: 16, height: 16 },
3463
- checked: a.selection.keys.includes(key),
3464
- onChange: (event) => a.setSelection({ zone, keys: event.target.checked ? [...a.selection.keys, key] : a.selection.keys.filter((k) => k !== key) })
3465
- }
3466
- ),
3467
- hidden && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HiddenBadge, { "data-testid": `row-hidden-${zone}-${index}`, children: t.hiddenBadge }),
3468
- a.hiddenName && (acts || hidden) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4755
+ return (0, import_react_dom3.createPortal)(
4756
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system.Flex, { gap: 0, alignItems: "center", "data-testid": `row-actions-${zone}-${index}`, role: "group", "aria-label": t.f("rowActions", { label }), children: [
4757
+ hidden && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HiddenBadge, { "data-testid": `row-hidden-${zone}-${index}`, children: t.hiddenBadge }),
4758
+ a.hiddenName && (acts || hidden) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3469
4759
  RowButton,
3470
4760
  {
3471
4761
  type: "button",
@@ -3475,10 +4765,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3475
4765
  "aria-label": t.f(hidden ? "showBlock" : "hideBlock", { label }),
3476
4766
  "data-testid": `row-hide-${zone}-${index}`,
3477
4767
  onClick: () => a.toggleHidden(zone, index),
3478
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: hidden ? "eyeOff" : "eye" })
4768
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: hidden ? "eyeOff" : "eye" })
3479
4769
  }
3480
4770
  ),
3481
- e.duplicate !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4771
+ e.duplicate !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3482
4772
  RowButton,
3483
4773
  {
3484
4774
  type: "button",
@@ -3487,10 +4777,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3487
4777
  "aria-label": t.f("duplicateBlock", { label }),
3488
4778
  "data-testid": `row-duplicate-${zone}-${index}`,
3489
4779
  onClick: () => a.duplicate(zone, index),
3490
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "duplicate" })
4780
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "duplicate" })
3491
4781
  }
3492
4782
  ),
3493
- e.clipboard !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
4783
+ e.clipboard !== false && acts && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
3494
4784
  RowButton,
3495
4785
  {
3496
4786
  type: "button",
@@ -3499,7 +4789,7 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3499
4789
  "aria-label": t.f("copyBlock", { label }),
3500
4790
  "data-testid": `row-copy-${zone}-${index}`,
3501
4791
  onClick: () => a.copy(zone, [key]),
3502
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "clipboard" })
4792
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "clipboard" })
3503
4793
  }
3504
4794
  )
3505
4795
  ] }),
@@ -3507,40 +4797,70 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3507
4797
  `${zone}:${index}`
3508
4798
  );
3509
4799
  }),
3510
- confirm && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
3511
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
3512
- confirm.marker && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
3513
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_design_system.Flex, { gap: 2, justifyContent: "flex-end", children: [
3514
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { variant: "tertiary", onClick: () => setConfirm(null), "data-testid": "row-confirm-cancel", children: t.cancel }),
3515
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { variant: "danger", onClick: confirmDelete, "data-testid": "row-confirm-ok", children: t.delete })
4800
+ confirm && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
4801
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
4802
+ confirm.marker && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
4803
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system.Flex, { gap: 2, justifyContent: "flex-end", children: [
4804
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Button, { variant: "tertiary", onClick: () => setConfirm(null), "data-testid": "row-confirm-cancel", children: t.cancel }),
4805
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Button, { variant: "danger", onClick: confirmDelete, "data-testid": "row-confirm-ok", children: t.delete })
3516
4806
  ] })
3517
4807
  ] }) })
3518
4808
  ] });
3519
4809
  }
3520
- function ZoneRowTools({ zone, actions: a }) {
3521
- if (!a || a.editor.clipboard === false) return null;
4810
+ function zoneMenuItems(zone, a) {
4811
+ if (!a || a.editor.clipboard === false) return [];
3522
4812
  const { t } = a;
3523
- const selecting = a.selection?.zone === zone.name;
3524
- const count = selecting ? a.selection.keys.length : 0;
3525
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3526
- zone.count > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3527
- Tool,
4813
+ return [
4814
+ zone.count > 0 && { label: t.selectBlocks, icon: "select", testid: `zone-select-${zone.name}`, onSelect: () => a.setSelection({ zone: zone.name, keys: [] }) },
4815
+ a.clip && !zone.full && a.pastable(zone.name) && { label: t.f("paste", { count: a.clip.rows.length }), icon: "paste", testid: `zone-paste-${zone.name}`, onSelect: () => a.paste(zone.name) }
4816
+ ].filter(Boolean);
4817
+ }
4818
+ function SelectionBar({ zone, actions: a }) {
4819
+ const { t } = a;
4820
+ const box = React4.useRef(null);
4821
+ const keys = a.selectable(zone.name);
4822
+ const chosen = a.selection.keys.filter((key) => keys.includes(key));
4823
+ const all = keys.length > 0 && chosen.length === keys.length;
4824
+ React4.useEffect(() => {
4825
+ if (box.current) box.current.indeterminate = chosen.length > 0 && !all;
4826
+ });
4827
+ const reason = chosen.length ? void 0 : t.copyNothing;
4828
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system.Flex, { gap: 2, alignItems: "center", "data-testid": `zone-selection-${zone.name}`, children: [
4829
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "inline-flex", alignItems: "center", gap: 8, cursor: "pointer" }, children: [
4830
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4831
+ "input",
4832
+ {
4833
+ ref: box,
4834
+ type: "checkbox",
4835
+ checked: all,
4836
+ "aria-label": chosen.length ? t.selectNone : t.selectAll,
4837
+ "data-testid": `zone-select-all-${zone.name}`,
4838
+ style: { margin: 0, width: 16, height: 16, cursor: "pointer" },
4839
+ onChange: () => a.setSelection({ zone: zone.name, keys: chosen.length ? [] : keys })
4840
+ }
4841
+ ),
4842
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Typography, { variant: "pi", fontWeight: "bold", "aria-live": "polite", "data-testid": `zone-selected-${zone.name}`, children: chosen.length ? t.f("selectedCount", { count: chosen.length }) : t.selectAll })
4843
+ ] }),
4844
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { title: reason, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4845
+ import_design_system.Button,
3528
4846
  {
3529
- icon: "select",
3530
- label: t.selectMode,
3531
- active: selecting,
3532
- "data-testid": `zone-select-${zone.name}`,
3533
- onClick: () => a.setSelection(selecting ? null : { zone: zone.name, keys: [] })
4847
+ size: "S",
4848
+ variant: "secondary",
4849
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "clipboard", size: 14 }),
4850
+ disabled: !chosen.length || a.busy,
4851
+ "aria-description": reason,
4852
+ onClick: () => a.copy(zone.name, chosen),
4853
+ "data-testid": `zone-copy-${zone.name}`,
4854
+ children: t.copy
3534
4855
  }
3535
- ),
3536
- selecting && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { size: "S", variant: "secondary", disabled: !count || a.busy, onClick: () => a.copy(zone.name, a.selection.keys), "data-testid": `zone-copy-${zone.name}`, children: t.f("copySelected", { count }) }),
3537
- a.clip && !zone.full && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_design_system.Button, { size: "S", variant: "secondary", startIcon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { name: "paste", size: 14 }), onClick: () => a.paste(zone.name), "data-testid": `zone-paste-${zone.name}`, children: t.f("paste", { count: a.clip.rows.length }) })
4856
+ ) }),
4857
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system.Button, { size: "S", variant: "tertiary", onClick: () => a.setSelection(null), "data-testid": `zone-select-done-${zone.name}`, children: t.selectDone })
3538
4858
  ] });
3539
4859
  }
3540
4860
 
3541
4861
  // admin/Gallery.tsx
3542
- var import_jsx_runtime5 = require("react/jsx-runtime");
3543
- var Columns = import_styled_components3.default.div`
4862
+ var import_jsx_runtime6 = require("react/jsx-runtime");
4863
+ var Columns = import_styled_components4.default.div`
3544
4864
  column-count: ${({ $columns }) => $columns};
3545
4865
  column-gap: 12px;
3546
4866
  > * {
@@ -3549,7 +4869,7 @@ var Columns = import_styled_components3.default.div`
3549
4869
  margin-bottom: 12px;
3550
4870
  }
3551
4871
  `;
3552
- var Tile = import_styled_components3.default.button`
4872
+ var Tile = import_styled_components4.default.button`
3553
4873
  display: flex;
3554
4874
  flex-direction: column;
3555
4875
  gap: 8px;
@@ -3569,13 +4889,13 @@ var Tile = import_styled_components3.default.button`
3569
4889
  outline-offset: 2px;
3570
4890
  }
3571
4891
  `;
3572
- var Clamp = (0, import_styled_components3.default)(import_design_system2.Typography)`
4892
+ var Clamp = (0, import_styled_components4.default)(import_design_system2.Typography)`
3573
4893
  display: -webkit-box;
3574
4894
  -webkit-line-clamp: 2;
3575
4895
  -webkit-box-orient: vertical;
3576
4896
  overflow: hidden;
3577
4897
  `;
3578
- var Slider = import_styled_components3.default.input`
4898
+ var Slider = import_styled_components4.default.input`
3579
4899
  appearance: none;
3580
4900
  -webkit-appearance: none;
3581
4901
  width: 8rem;
@@ -3629,7 +4949,7 @@ var remember = (key, value) => {
3629
4949
  } catch {
3630
4950
  }
3631
4951
  };
3632
- var Frame = import_styled_components3.default.div`
4952
+ var Frame = import_styled_components4.default.div`
3633
4953
  width: 100%;
3634
4954
  overflow: hidden;
3635
4955
  border-radius: 4px;
@@ -3652,9 +4972,9 @@ function Thumb({
3652
4972
  blank
3653
4973
  }) {
3654
4974
  const key = candidates.join("|");
3655
- const [state, setState] = React4.useState({ key, index: 0 });
4975
+ const [state, setState] = React5.useState({ key, index: 0 });
3656
4976
  const index = state.key === key ? state.index : 0;
3657
- const resolved = React4.useRef("");
4977
+ const resolved = React5.useRef("");
3658
4978
  const report = (value) => {
3659
4979
  const tag = `${key}:${value}`;
3660
4980
  if (resolved.current !== tag) {
@@ -3662,11 +4982,11 @@ function Thumb({
3662
4982
  onResolved?.(value);
3663
4983
  }
3664
4984
  };
3665
- React4.useEffect(() => {
4985
+ React5.useEffect(() => {
3666
4986
  if (index >= candidates.length) report(-1);
3667
4987
  });
3668
4988
  if (index >= candidates.length)
3669
- return blank ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4989
+ return blank ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3670
4990
  Wireframe,
3671
4991
  {
3672
4992
  template,
@@ -3674,7 +4994,7 @@ function Thumb({
3674
4994
  noPreview
3675
4995
  }
3676
4996
  ) });
3677
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4997
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3678
4998
  "img",
3679
4999
  {
3680
5000
  src: candidates[index],
@@ -3686,12 +5006,12 @@ function Thumb({
3686
5006
  candidates[index]
3687
5007
  ) });
3688
5008
  }
3689
- var Layout = import_styled_components3.default.div`
5009
+ var Layout = import_styled_components4.default.div`
3690
5010
  display: flex;
3691
5011
  height: min(70vh, 720px);
3692
5012
  min-height: 320px;
3693
5013
  `;
3694
- var Side = import_styled_components3.default.nav`
5014
+ var Side = import_styled_components4.default.nav`
3695
5015
  flex: 0 0 ${({ $collapsed }) => $collapsed ? "48px" : "200px"};
3696
5016
  display: flex;
3697
5017
  flex-direction: column;
@@ -3701,7 +5021,7 @@ var Side = import_styled_components3.default.nav`
3701
5021
  border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
3702
5022
  overflow-y: auto;
3703
5023
  `;
3704
- var NavItem = import_styled_components3.default.button`
5024
+ var NavItem = import_styled_components4.default.button`
3705
5025
  display: flex;
3706
5026
  align-items: center;
3707
5027
  justify-content: ${({ $collapsed }) => $collapsed ? "center" : "flex-start"};
@@ -3733,17 +5053,17 @@ var NavItem = import_styled_components3.default.button`
3733
5053
  font-size: 12px;
3734
5054
  }
3735
5055
  `;
3736
- var Main = import_styled_components3.default.div`
5056
+ var Main = import_styled_components4.default.div`
3737
5057
  flex: 1;
3738
5058
  min-width: 0;
3739
5059
  display: flex;
3740
5060
  flex-direction: column;
3741
5061
  gap: 12px;
3742
5062
  `;
3743
- var Menu = import_styled_components3.default.div`
5063
+ var Menu = import_styled_components4.default.div`
3744
5064
  position: relative;
3745
5065
  `;
3746
- var MenuButton = import_styled_components3.default.button`
5066
+ var MenuButton = import_styled_components4.default.button`
3747
5067
  display: inline-flex;
3748
5068
  align-items: center;
3749
5069
  gap: 6px;
@@ -3761,7 +5081,7 @@ var MenuButton = import_styled_components3.default.button`
3761
5081
  outline-offset: 1px;
3762
5082
  }
3763
5083
  `;
3764
- var Popover = import_styled_components3.default.div`
5084
+ var Popover = import_styled_components4.default.div`
3765
5085
  position: absolute;
3766
5086
  top: calc(100% + 4px);
3767
5087
  left: 0;
@@ -3792,7 +5112,7 @@ var Popover = import_styled_components3.default.div`
3792
5112
  color: ${({ theme }) => theme.colors.neutral500};
3793
5113
  }
3794
5114
  `;
3795
- var Chip = import_styled_components3.default.button`
5115
+ var Chip = import_styled_components4.default.button`
3796
5116
  display: inline-flex;
3797
5117
  align-items: center;
3798
5118
  gap: 4px;
@@ -3804,7 +5124,7 @@ var Chip = import_styled_components3.default.button`
3804
5124
  color: ${({ theme }) => theme.colors.primary700};
3805
5125
  background: ${({ theme }) => theme.colors.primary100};
3806
5126
  `;
3807
- var Badge = import_styled_components3.default.span`
5127
+ var Badge = import_styled_components4.default.span`
3808
5128
  padding: 1px 6px;
3809
5129
  border-radius: 3px;
3810
5130
  font-size: 10px;
@@ -3815,14 +5135,14 @@ var Badge = import_styled_components3.default.span`
3815
5135
  color: ${({ theme }) => theme.colors.neutral0};
3816
5136
  background: ${({ theme }) => theme.colors.neutral800};
3817
5137
  `;
3818
- var CardBox = import_styled_components3.default.div`
5138
+ var CardBox = import_styled_components4.default.div`
3819
5139
  position: relative;
3820
5140
  &:hover .bs-quick,
3821
5141
  &:focus-within .bs-quick {
3822
5142
  opacity: 1;
3823
5143
  }
3824
5144
  `;
3825
- var CardBadges = import_styled_components3.default.div`
5145
+ var CardBadges = import_styled_components4.default.div`
3826
5146
  position: absolute;
3827
5147
  top: 14px;
3828
5148
  left: 14px;
@@ -3832,7 +5152,7 @@ var CardBadges = import_styled_components3.default.div`
3832
5152
  gap: 4px;
3833
5153
  pointer-events: none;
3834
5154
  `;
3835
- var Round = import_styled_components3.default.button`
5155
+ var Round = import_styled_components4.default.button`
3836
5156
  position: absolute;
3837
5157
  right: 14px;
3838
5158
  display: inline-flex;
@@ -3855,7 +5175,7 @@ var Round = import_styled_components3.default.button`
3855
5175
  transition: opacity 120ms;
3856
5176
  }
3857
5177
  `;
3858
- var Mono = import_styled_components3.default.code`
5178
+ var Mono = import_styled_components4.default.code`
3859
5179
  font-size: 12px;
3860
5180
  color: ${({ theme }) => theme.colors.neutral600};
3861
5181
  `;
@@ -3871,9 +5191,9 @@ var TYPE_ICONS = { hero: "hero", text: "text", media: "image", listing: "list",
3871
5191
  var FILTER_MENUS = ["tags", "media", "content"];
3872
5192
  var toggled = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];
3873
5193
  function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3874
- const [open, setOpen] = React4.useState(false);
3875
- const ref = React4.useRef(null);
3876
- React4.useEffect(() => {
5194
+ const [open, setOpen] = React5.useState(false);
5195
+ const ref = React5.useRef(null);
5196
+ React5.useEffect(() => {
3877
5197
  if (!open) return;
3878
5198
  const down = (event) => {
3879
5199
  if (!ref.current?.contains(event.target)) setOpen(false);
@@ -3891,8 +5211,8 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3891
5211
  window.removeEventListener("keydown", key, true);
3892
5212
  };
3893
5213
  }, [open]);
3894
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Menu, { ref, "data-testid": `gallery-filter-${name}`, children: [
3895
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
5214
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Menu, { ref, "data-testid": `gallery-filter-${name}`, children: [
5215
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3896
5216
  MenuButton,
3897
5217
  {
3898
5218
  type: "button",
@@ -3901,12 +5221,12 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3901
5221
  onClick: () => setOpen(!open),
3902
5222
  children: [
3903
5223
  picked.length ? `${label} (${picked.length})` : label,
3904
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "chevron", size: 14 })
5224
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: "chevron", size: 14 })
3905
5225
  ]
3906
5226
  }
3907
5227
  ),
3908
- open && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Popover, { role: "group", "aria-label": label, children: options.map(([value, count]) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { children: [
3909
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5228
+ open && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Popover, { role: "group", "aria-label": label, children: options.map(([value, count]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
5229
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3910
5230
  "input",
3911
5231
  {
3912
5232
  type: "checkbox",
@@ -3915,23 +5235,23 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3915
5235
  "data-testid": `gallery-option-${name}-${value}`
3916
5236
  }
3917
5237
  ),
3918
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: labelOf(value) }),
3919
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-count", children: count })
5238
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: labelOf(value) }),
5239
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "bs-count", children: count })
3920
5240
  ] }, value)) })
3921
5241
  ] });
3922
5242
  }
3923
5243
  function Badges({ entry, t, tags }) {
3924
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
3925
- entry.facets.map((facet) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: t.facets[facet] || facet }, facet)),
3926
- tags && entry.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: tag }, `tag:${tag}`))
5244
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5245
+ entry.facets.map((facet) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { children: t.facets[facet] || facet }, facet)),
5246
+ tags && entry.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { children: tag }, `tag:${tag}`))
3927
5247
  ] });
3928
5248
  }
3929
5249
  function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, onStar }) {
3930
5250
  const t = useMessages();
3931
- const timer = React4.useRef(null);
3932
- React4.useEffect(() => () => clearTimeout(timer.current), []);
3933
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(CardBox, { title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
3934
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
5251
+ const timer = React5.useRef(null);
5252
+ React5.useEffect(() => () => clearTimeout(timer.current), []);
5253
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(CardBox, { title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
5254
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
3935
5255
  Tile,
3936
5256
  {
3937
5257
  type: "button",
@@ -3948,7 +5268,7 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3948
5268
  onInsert();
3949
5269
  },
3950
5270
  children: [
3951
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5271
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3952
5272
  Thumb,
3953
5273
  {
3954
5274
  candidates: entry.candidates,
@@ -3957,9 +5277,9 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3957
5277
  noPreview: t.noPreview
3958
5278
  }
3959
5279
  ),
3960
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
3961
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
3962
- showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5280
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
5281
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
5282
+ showFields && entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3963
5283
  import_design_system2.Typography,
3964
5284
  {
3965
5285
  variant: "pi",
@@ -3972,8 +5292,8 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3972
5292
  ]
3973
5293
  }
3974
5294
  ),
3975
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CardBadges, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badges, { entry, t }) }),
3976
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5295
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CardBadges, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badges, { entry, t }) }),
5296
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3977
5297
  Round,
3978
5298
  {
3979
5299
  type: "button",
@@ -3984,10 +5304,10 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3984
5304
  title: starred ? t.unstar : t.star,
3985
5305
  onClick: onStar,
3986
5306
  "data-testid": `gallery-star-${entry.uid}`,
3987
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "star", size: 16, filled: starred })
5307
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: "star", size: 16, filled: starred })
3988
5308
  }
3989
5309
  ),
3990
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5310
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
3991
5311
  Round,
3992
5312
  {
3993
5313
  type: "button",
@@ -3998,19 +5318,19 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3998
5318
  title: t.f("quickInsert", { label: entry.label }),
3999
5319
  onClick: onInsert,
4000
5320
  "data-testid": `gallery-quick-${entry.uid}`,
4001
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "plus", size: 16 })
5321
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: "plus", size: 16 })
4002
5322
  }
4003
5323
  )
4004
5324
  ] });
4005
5325
  }
4006
- var Scrim = import_styled_components3.default.div`
5326
+ var Scrim = import_styled_components4.default.div`
4007
5327
  position: absolute;
4008
5328
  inset: 0;
4009
5329
  z-index: 4;
4010
5330
  opacity: 0.35;
4011
5331
  background: ${({ theme }) => theme.colors.neutral800};
4012
5332
  `;
4013
- var Panel = import_styled_components3.default.section`
5333
+ var Panel = import_styled_components4.default.section`
4014
5334
  position: absolute;
4015
5335
  inset: 16px;
4016
5336
  z-index: 5;
@@ -4023,7 +5343,7 @@ var Panel = import_styled_components3.default.section`
4023
5343
  box-shadow: ${({ theme }) => theme.shadows?.popupShadow || "0 8px 32px rgba(33, 33, 52, 0.3)"};
4024
5344
  transform-origin: top left;
4025
5345
  `;
4026
- var Stage = import_styled_components3.default.div`
5346
+ var Stage = import_styled_components4.default.div`
4027
5347
  position: relative;
4028
5348
  flex: 1;
4029
5349
  min-height: 0;
@@ -4032,7 +5352,7 @@ var Stage = import_styled_components3.default.div`
4032
5352
  background-image: ${({ theme }) => stageBackground(theme).backgroundImage};
4033
5353
  background-size: 24px 24px;
4034
5354
  `;
4035
- var Still = import_styled_components3.default.div`
5355
+ var Still = import_styled_components4.default.div`
4036
5356
  position: absolute;
4037
5357
  inset: 0;
4038
5358
  /* Hidden once the live page has faded in over it (device widths would show it in the gutters). */
@@ -4051,7 +5371,7 @@ var Still = import_styled_components3.default.div`
4051
5371
  object-fit: contain;
4052
5372
  }
4053
5373
  `;
4054
- var Live = import_styled_components3.default.iframe`
5374
+ var Live = import_styled_components4.default.iframe`
4055
5375
  position: absolute;
4056
5376
  top: 0;
4057
5377
  border: 0;
@@ -4063,14 +5383,14 @@ var Live = import_styled_components3.default.iframe`
4063
5383
  transition: none;
4064
5384
  }
4065
5385
  `;
4066
- var Strip = import_styled_components3.default.div`
5386
+ var Strip = import_styled_components4.default.div`
4067
5387
  display: flex;
4068
5388
  flex-direction: column;
4069
5389
  gap: 6px;
4070
5390
  padding: 10px 12px;
4071
5391
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
4072
5392
  `;
4073
- var FieldsButton = import_styled_components3.default.button`
5393
+ var FieldsButton = import_styled_components4.default.button`
4074
5394
  border: 0;
4075
5395
  padding: 0;
4076
5396
  cursor: pointer;
@@ -4101,9 +5421,9 @@ var flip = (panel, scrim, card, back) => {
4101
5421
  var newChannel = () => crypto.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`;
4102
5422
  function useLiveSource(entry, config, components, get, contentType, locale) {
4103
5423
  const editor = config?.editor || {};
4104
- const [native, setNative] = React4.useState(null);
5424
+ const [native, setNative] = React5.useState(null);
4105
5425
  const plain = editor.blockPreviewUrl ? blockPreviewSrc(editor.blockPreviewUrl, entry.uid, { locale: locale || "" }) : null;
4106
- React4.useEffect(() => {
5426
+ React5.useEffect(() => {
4107
5427
  if (editor.blockPreviewUrl || editor.previewUrl || !contentType || !get) return;
4108
5428
  let active = true;
4109
5429
  get(`/content-manager/preview/url/${contentType}?${new URLSearchParams({ status: "draft", ...locale ? { locale } : {} })}`).then(({ data }) => {
@@ -4114,7 +5434,7 @@ function useLiveSource(entry, config, components, get, contentType, locale) {
4114
5434
  active = false;
4115
5435
  };
4116
5436
  }, [editor.blockPreviewUrl, editor.previewUrl, contentType, locale, get]);
4117
- const channel = React4.useMemo(newChannel, []);
5437
+ const channel = React5.useMemo(newChannel, []);
4118
5438
  if (editor.blockPreviewUrl) return plain ? { kind: "plain", src: plain, origin: "", channel } : null;
4119
5439
  const base = editor.previewUrl || native;
4120
5440
  if (!base) return null;
@@ -4129,18 +5449,18 @@ function useLiveSource(entry, config, components, get, contentType, locale) {
4129
5449
  var LIVE_TIMEOUT = 8e3;
4130
5450
  function Magnify({ entry, palette, config, components, get, contentType, locale, starred, onStar, onInsert, onClose, cardOf }) {
4131
5451
  const t = useMessages();
4132
- const panel = React4.useRef(null);
4133
- const scrim = React4.useRef(null);
4134
- const closeButton = React4.useRef(null);
4135
- const frame2 = React4.useRef(null);
4136
- const closing = React4.useRef(false);
4137
- const [stageEl, setStageEl] = React4.useState(null);
5452
+ const panel = React5.useRef(null);
5453
+ const scrim = React5.useRef(null);
5454
+ const closeButton = React5.useRef(null);
5455
+ const frame2 = React5.useRef(null);
5456
+ const closing = React5.useRef(false);
5457
+ const [stageEl, setStageEl] = React5.useState(null);
4138
5458
  const stage = useStageSize(stageEl);
4139
- const [device, setDevice] = React4.useState("fit");
4140
- const [fields, setFields] = React4.useState(false);
4141
- const [state, setState] = React4.useState("loading");
5459
+ const [device, setDevice] = React5.useState("fit");
5460
+ const [fields, setFields] = React5.useState(false);
5461
+ const [state, setState] = React5.useState("loading");
4142
5462
  const live = useLiveSource(entry, config, components, get, contentType, locale);
4143
- React4.useLayoutEffect(() => {
5463
+ React5.useLayoutEffect(() => {
4144
5464
  flip(panel.current, scrim.current, cardOf(entry.uid), false);
4145
5465
  closeButton.current?.querySelector("button")?.focus({ preventScroll: true });
4146
5466
  }, []);
@@ -4156,9 +5476,9 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4156
5476
  if (animation) animation.onfinish = done;
4157
5477
  else done();
4158
5478
  };
4159
- const closeRef = React4.useRef(close);
5479
+ const closeRef = React5.useRef(close);
4160
5480
  closeRef.current = close;
4161
- React4.useEffect(() => {
5481
+ React5.useEffect(() => {
4162
5482
  const key = (event) => {
4163
5483
  if (event.key !== "Escape") return;
4164
5484
  event.stopPropagation();
@@ -4169,7 +5489,7 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4169
5489
  return () => window.removeEventListener("keydown", key, true);
4170
5490
  }, []);
4171
5491
  const src = live?.src;
4172
- React4.useEffect(() => {
5492
+ React5.useEffect(() => {
4173
5493
  if (!live) return;
4174
5494
  setState("loading");
4175
5495
  const timer = setTimeout(() => setState((s) => s === "ready" ? s : "failed"), LIVE_TIMEOUT);
@@ -4198,11 +5518,11 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4198
5518
  if (live?.kind === "plain") setState("ready");
4199
5519
  else frame2.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel: live.channel, type: "ping" }, live.origin);
4200
5520
  };
4201
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4202
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Scrim, { ref: scrim, onClick: close, "data-testid": "gallery-magnify-scrim" }),
4203
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Panel, { ref: panel, "aria-label": entry.label, "data-testid": "gallery-detail", "data-live": live ? state : "none", children: [
4204
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, padding: 2, alignItems: "center", justifyContent: "space-between", children: [
4205
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { gap: 1, role: "group", "aria-label": t.deviceGroup, "data-testid": "gallery-magnify-devices", children: Object.keys(DEVICES).map((value) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5521
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5522
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Scrim, { ref: scrim, onClick: close, "data-testid": "gallery-magnify-scrim" }),
5523
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Panel, { ref: panel, "aria-label": entry.label, "data-testid": "gallery-detail", "data-live": live ? state : "none", children: [
5524
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 2, padding: 2, alignItems: "center", justifyContent: "space-between", children: [
5525
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Flex, { gap: 1, role: "group", "aria-label": t.deviceGroup, "data-testid": "gallery-magnify-devices", children: Object.keys(DEVICES).map((value) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4206
5526
  Tool,
4207
5527
  {
4208
5528
  icon: value,
@@ -4212,12 +5532,12 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4212
5532
  },
4213
5533
  value
4214
5534
  )) }),
4215
- live && state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "gallery-magnify-note", children: t.livePreviewFailed }),
4216
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: closeButton, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "close", label: t.closeDetail, onClick: close }) })
5535
+ live && state === "failed" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "gallery-magnify-note", children: t.livePreviewFailed }),
5536
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: closeButton, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "close", label: t.closeDetail, onClick: close }) })
4217
5537
  ] }),
4218
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Stage, { ref: setStageEl, $device: device !== "fit", "data-device": device, children: [
4219
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Still, { $covered: Boolean(live) && state === "ready", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview, eager: true }) }),
4220
- live && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5538
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Stage, { ref: setStageEl, $device: device !== "fit", "data-device": device, children: [
5539
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Still, { $covered: Boolean(live) && state === "ready", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview, eager: true }) }),
5540
+ live && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4221
5541
  Live,
4222
5542
  {
4223
5543
  ref: frame2,
@@ -4233,23 +5553,23 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4233
5553
  live.src
4234
5554
  )
4235
5555
  ] }),
4236
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Strip, { children: [
4237
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4238
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "omega", fontWeight: "bold", tag: "h3", ellipsis: true, children: entry.label }),
4239
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Mono, { children: entry.uid }),
4240
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badge, { children: t.typologies[entry.typology] || entry.typology }),
4241
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Badges, { entry, t, tags: true }),
4242
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
4243
- entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FieldsButton, { type: "button", "aria-expanded": fields, onClick: () => setFields(!fields), "data-testid": "gallery-detail-fields-toggle", children: `${t.showFields} (${entry.fields.length})` }),
4244
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "star", label: starred ? t.unstar : t.star, active: starred, onClick: onStar, "data-testid": "gallery-detail-star" }),
4245
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { onClick: onInsert, "data-testid": "gallery-insert", children: t.insert })
5556
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Strip, { children: [
5557
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", wrap: "wrap", children: [
5558
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "omega", fontWeight: "bold", tag: "h3", ellipsis: true, children: entry.label }),
5559
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Mono, { children: entry.uid }),
5560
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { children: t.typologies[entry.typology] || entry.typology }),
5561
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badges, { entry, t, tags: true }),
5562
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
5563
+ entry.fields.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FieldsButton, { type: "button", "aria-expanded": fields, onClick: () => setFields(!fields), "data-testid": "gallery-detail-fields-toggle", children: `${t.showFields} (${entry.fields.length})` }),
5564
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "star", label: starred ? t.unstar : t.star, active: starred, onClick: onStar, "data-testid": "gallery-detail-star" }),
5565
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Button, { onClick: onInsert, "data-testid": "gallery-insert", children: t.insert })
4246
5566
  ] })
4247
5567
  ] }),
4248
- entry.description && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Clamp, { variant: "pi", textColor: "neutral700", children: entry.description }),
4249
- fields && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { gap: 3, wrap: "wrap", "data-testid": "gallery-detail-fields", children: entry.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral800", children: [
4250
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: field.name }),
5568
+ entry.description && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Clamp, { variant: "pi", textColor: "neutral700", children: entry.description }),
5569
+ fields && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Flex, { gap: 3, wrap: "wrap", "data-testid": "gallery-detail-fields", children: entry.fields.map((field) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Typography, { variant: "pi", textColor: "neutral800", children: [
5570
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: field.name }),
4251
5571
  " ",
4252
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Mono, { children: field.type })
5572
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Mono, { children: field.type })
4253
5573
  ] }, field.name)) })
4254
5574
  ] })
4255
5575
  ] })
@@ -4269,22 +5589,22 @@ function ZoneGallery({
4269
5589
  locale
4270
5590
  }) {
4271
5591
  const t = useMessages();
4272
- const grid = React4.useRef(null);
5592
+ const grid = React5.useRef(null);
4273
5593
  const cardOf = (uid) => grid.current?.querySelector(`[data-testid="blockscene-${CSS.escape(uid)}"]`) || null;
4274
- const [ownOpen, setOwnOpen] = React4.useState(false);
5594
+ const [ownOpen, setOwnOpen] = React5.useState(false);
4275
5595
  const open = controlled ? controlled.open : ownOpen;
4276
5596
  const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
4277
- const [query, setQuery] = React4.useState("");
4278
- const [view, setView] = React4.useState("all");
4279
- const [picked, setPicked] = React4.useState(NO_FILTERS);
4280
- const [detail, setDetail] = React4.useState(null);
4281
- const [collapsed, setCollapsed] = React4.useState(readCollapsed);
4282
- const [prefs, setPrefs] = React4.useState({ starred: [], recent: [] });
4283
- const [showFields, setShowFields] = React4.useState(readShowFields);
4284
- const [columns, setColumns] = React4.useState(readColumns);
4285
- const [config, setConfig] = React4.useState(null);
4286
- const [error, setError] = React4.useState("");
4287
- React4.useEffect(() => {
5597
+ const [query, setQuery] = React5.useState("");
5598
+ const [view, setView] = React5.useState("all");
5599
+ const [picked, setPicked] = React5.useState(NO_FILTERS);
5600
+ const [detail, setDetail] = React5.useState(null);
5601
+ const [collapsed, setCollapsed] = React5.useState(readCollapsed);
5602
+ const [prefs, setPrefs] = React5.useState({ starred: [], recent: [] });
5603
+ const [showFields, setShowFields] = React5.useState(readShowFields);
5604
+ const [columns, setColumns] = React5.useState(readColumns);
5605
+ const [config, setConfig] = React5.useState(null);
5606
+ const [error, setError] = React5.useState("");
5607
+ React5.useEffect(() => {
4288
5608
  if (controlled) return;
4289
5609
  const onClick = (event) => {
4290
5610
  const button = event.target?.closest?.("button");
@@ -4296,7 +5616,7 @@ function ZoneGallery({
4296
5616
  document.addEventListener("click", onClick, true);
4297
5617
  return () => document.removeEventListener("click", onClick, true);
4298
5618
  }, [controlled, zone.name, zone.label]);
4299
- React4.useEffect(() => {
5619
+ React5.useEffect(() => {
4300
5620
  if (!open) return;
4301
5621
  let active = true;
4302
5622
  setError("");
@@ -4363,7 +5683,7 @@ function ZoneGallery({
4363
5683
  setCollapsed(!collapsed);
4364
5684
  remember(SIDEBAR_KEY, collapsed ? "expanded" : "collapsed");
4365
5685
  };
4366
- const nav = (key, icon, label, count) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
5686
+ const nav = (key, icon, label, count) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4367
5687
  NavItem,
4368
5688
  {
4369
5689
  type: "button",
@@ -4375,34 +5695,25 @@ function ZoneGallery({
4375
5695
  onClick: () => setView(key),
4376
5696
  "data-testid": `gallery-nav-${key}`,
4377
5697
  children: [
4378
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: icon }),
4379
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
4380
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-label", children: label }),
4381
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "bs-count", children: count })
5698
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: icon }),
5699
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5700
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "bs-label", children: label }),
5701
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "bs-count", children: count })
4382
5702
  ] })
4383
5703
  ]
4384
5704
  },
4385
5705
  key
4386
5706
  );
4387
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5707
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4388
5708
  Modal2,
4389
5709
  {
4390
5710
  open,
4391
5711
  onOpenChange: setOpen,
4392
5712
  title: t.gallery,
4393
- trigger: controlled ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
4394
- import_design_system2.Button,
4395
- {
4396
- variant: "secondary",
4397
- fullWidth: true,
4398
- onClick: () => setOpen(true),
4399
- "data-testid": `open-gallery-${zone.name}`,
4400
- children: t.add
4401
- }
4402
- ),
4403
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Layout, { children: [
4404
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Side, { $collapsed: collapsed, "aria-label": t.gallery, "data-testid": `gallery-sidebar-${zone.name}`, "data-collapsed": collapsed, children: [
4405
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { justifyContent: collapsed ? "center" : "flex-end", paddingBottom: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5713
+ trigger: null,
5714
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Layout, { children: [
5715
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Side, { $collapsed: collapsed, "aria-label": t.gallery, "data-testid": `gallery-sidebar-${zone.name}`, "data-collapsed": collapsed, children: [
5716
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Flex, { justifyContent: collapsed ? "center" : "flex-end", paddingBottom: 2, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4406
5717
  Tool,
4407
5718
  {
4408
5719
  icon: "sidebar",
@@ -4411,19 +5722,19 @@ function ZoneGallery({
4411
5722
  "data-testid": "gallery-sidebar-toggle"
4412
5723
  }
4413
5724
  ) }),
4414
- options && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
5725
+ options && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
4415
5726
  nav("all", "grid", t.nav.all, options.total),
4416
5727
  nav("recent", "clock", t.nav.recent, inZone(prefs.recent).length),
4417
5728
  nav("starred", "star", t.nav.starred, inZone(prefs.starred).length),
4418
- !collapsed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Box, { paddingTop: 4, paddingBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", children: t.typologiesTitle }) }),
5729
+ !collapsed && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Box, { paddingTop: 4, paddingBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", children: t.typologiesTitle }) }),
4419
5730
  options.typologies.map(
4420
5731
  ([name, count]) => nav(name, TYPE_ICONS[name] || "text", t.typologies[name] || name, count)
4421
5732
  )
4422
5733
  ] })
4423
5734
  ] }),
4424
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Main, { children: [
4425
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
4426
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5735
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Main, { children: [
5736
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
5737
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4427
5738
  import_design_system2.Typography,
4428
5739
  {
4429
5740
  variant: "omega",
@@ -4435,7 +5746,7 @@ function ZoneGallery({
4435
5746
  children: filtering ? t.f("countFiltered", { shown: entries.length, total: options?.total || 0 }) : t.f("countAll", { count: options?.total || 0 })
4436
5747
  }
4437
5748
  ),
4438
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5749
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4439
5750
  import_design_system2.Searchbar,
4440
5751
  {
4441
5752
  name: `block-search-${zone.name}`,
@@ -4447,7 +5758,7 @@ function ZoneGallery({
4447
5758
  children: t.search
4448
5759
  }
4449
5760
  ) }),
4450
- options && FILTER_MENUS.filter((menu) => options[menu].length > 0).map((menu) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5761
+ options && FILTER_MENUS.filter((menu) => options[menu].length > 0).map((menu) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4451
5762
  FilterMenu,
4452
5763
  {
4453
5764
  name: menu,
@@ -4459,7 +5770,7 @@ function ZoneGallery({
4459
5770
  },
4460
5771
  menu
4461
5772
  )),
4462
- Toggle && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5773
+ Toggle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4463
5774
  Toggle,
4464
5775
  {
4465
5776
  name: `block-fields-${zone.name}`,
@@ -4469,9 +5780,9 @@ function ZoneGallery({
4469
5780
  onChange: changeShowFields
4470
5781
  }
4471
5782
  ),
4472
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", children: [
4473
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
4474
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5783
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 2, alignItems: "center", children: [
5784
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
5785
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4475
5786
  Slider,
4476
5787
  {
4477
5788
  type: "range",
@@ -4484,11 +5795,11 @@ function ZoneGallery({
4484
5795
  onChange: (e) => changeColumns(Number(e.target.value))
4485
5796
  }
4486
5797
  ),
4487
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", children: columns })
5798
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "pi", fontWeight: "bold", children: columns })
4488
5799
  ] })
4489
5800
  ] }),
4490
- chips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", "data-testid": "gallery-chips", children: [
4491
- chips.map(({ menu, value }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
5801
+ chips.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 2, wrap: "wrap", "data-testid": "gallery-chips", children: [
5802
+ chips.map(({ menu, value }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
4492
5803
  Chip,
4493
5804
  {
4494
5805
  type: "button",
@@ -4496,16 +5807,16 @@ function ZoneGallery({
4496
5807
  onClick: () => setPicked({ ...picked, [menu]: picked[menu].filter((item) => item !== value) }),
4497
5808
  children: [
4498
5809
  labelOf(menu, value),
4499
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { name: "close", size: 12 })
5810
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: "close", size: 12 })
4500
5811
  ]
4501
5812
  },
4502
5813
  `${menu}:${value}`
4503
5814
  )),
4504
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
5815
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
4505
5816
  ] }),
4506
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
4507
- error ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
4508
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5817
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "pi", textColor: "neutral600", children: t.example }),
5818
+ error ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { children: t.loading }) : entries.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
5819
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4509
5820
  import_design_system2.Flex,
4510
5821
  {
4511
5822
  direction: "column",
@@ -4513,9 +5824,9 @@ function ZoneGallery({
4513
5824
  gap: 4,
4514
5825
  style: { overflowY: "auto", flex: 1, minHeight: 0, padding: "4px" },
4515
5826
  children: (view === "recent" ? [{ typology: "recent", entries }] : groupEntries(entries)).map(
4516
- ({ typology, entries: items }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
4517
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${typology}`, children: `${typology === "recent" ? t.nav.recent : t.typologies[typology] || typology} (${items.length})` }),
4518
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5827
+ ({ typology, entries: items2 }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
5828
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${typology}`, children: `${typology === "recent" ? t.nav.recent : t.typologies[typology] || typology} (${items2.length})` }),
5829
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Columns, { $columns: columns, children: items2.map((entry) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4519
5830
  Card,
4520
5831
  {
4521
5832
  entry,
@@ -4532,7 +5843,7 @@ function ZoneGallery({
4532
5843
  )
4533
5844
  }
4534
5845
  ),
4535
- chosen && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
5846
+ chosen && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4536
5847
  Magnify,
4537
5848
  {
4538
5849
  entry: chosen,
@@ -4550,9 +5861,9 @@ function ZoneGallery({
4550
5861
  },
4551
5862
  chosen.uid
4552
5863
  )
4553
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", children: [
4554
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { children: t.empty }),
4555
- filtering && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
5864
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system2.Flex, { gap: 3, alignItems: "center", children: [
5865
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Typography, { children: t.empty }),
5866
+ filtering && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Button, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
4556
5867
  ] })
4557
5868
  ] })
4558
5869
  ] })
@@ -4574,12 +5885,12 @@ function useInitialAccordions({
4574
5885
  contentType,
4575
5886
  userId
4576
5887
  }) {
4577
- const applied = React4.useRef("");
4578
- const user = React4.useRef(userId);
5888
+ const applied = React5.useRef("");
5889
+ const user = React5.useRef(userId);
4579
5890
  user.current = userId;
4580
- const latest = React4.useRef(zones);
5891
+ const latest = React5.useRef(zones);
4581
5892
  latest.current = zones;
4582
- React4.useEffect(() => {
5893
+ React5.useEffect(() => {
4583
5894
  if (!editor?.enabled || !docKey || applied.current === docKey) return;
4584
5895
  if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
4585
5896
  applied.current = docKey;
@@ -4618,7 +5929,7 @@ function useInitialAccordions({
4618
5929
  setAll(
4619
5930
  list,
4620
5931
  initialState(editor, readMemory(storage2(), key)) === "open",
4621
- import_react_dom3.unstable_batchedUpdates
5932
+ import_react_dom4.unstable_batchedUpdates
4622
5933
  );
4623
5934
  }
4624
5935
  }, 200);
@@ -4626,24 +5937,31 @@ function useInitialAccordions({
4626
5937
  }, [docKey, editor?.enabled, editor?.initialState, contentType]);
4627
5938
  }
4628
5939
  var ZONE_ATTR = "data-blockscene-zone-controls";
4629
- function useLabelAnchor(zone, enabled) {
4630
- const [el, setEl] = React4.useState(null);
4631
- React4.useEffect(() => {
5940
+ function useZoneAnchor(zone, enabled) {
5941
+ const [el, setEl] = React5.useState(null);
5942
+ const filled = zone.count > 0;
5943
+ React5.useEffect(() => {
4632
5944
  if (!enabled) return;
4633
5945
  let frame2 = 0;
4634
5946
  const sync = () => {
4635
- const list = findZoneList(zone.label);
4636
- const row = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim());
5947
+ let host = null, after = null;
5948
+ if (filled) {
5949
+ const list = findZoneList(zone.label);
5950
+ host = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim()) || null;
5951
+ } else {
5952
+ after = [...document.querySelectorAll("button")].find((button) => isNativeAddButton(button, zone)) || null;
5953
+ host = after?.parentElement || null;
5954
+ }
4637
5955
  let anchor = document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`);
4638
- if (anchor && anchor.parentElement !== row) {
5956
+ if (anchor && (anchor.parentElement !== host || after && anchor.previousElementSibling !== after)) {
4639
5957
  anchor.remove();
4640
5958
  anchor = null;
4641
5959
  }
4642
- if (!anchor && row) {
5960
+ if (!anchor && host) {
4643
5961
  anchor = document.createElement("span");
4644
5962
  anchor.setAttribute(ZONE_ATTR, zone.name);
4645
- anchor.style.cssText = "display:inline-flex;align-items:center;margin-left:8px";
4646
- row.appendChild(anchor);
5963
+ anchor.style.cssText = "display:inline-flex;align-items:center;margin-left:8px;white-space:nowrap";
5964
+ host.insertBefore(anchor, after ? after.nextSibling : null);
4647
5965
  }
4648
5966
  setEl(anchor);
4649
5967
  };
@@ -4661,29 +5979,69 @@ function useLabelAnchor(zone, enabled) {
4661
5979
  document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`)?.remove();
4662
5980
  setEl(null);
4663
5981
  };
4664
- }, [zone.name, zone.label, enabled]);
5982
+ }, [zone.name, zone.label, enabled, filled]);
4665
5983
  return el;
4666
5984
  }
4667
- function ZoneControls({ zone, editor, contentType, userId, tools }) {
5985
+ function useRowStates(zone, enabled) {
5986
+ const [state, setState] = React5.useState({ closed: false, open: false });
5987
+ React5.useEffect(() => {
5988
+ if (!enabled) return;
5989
+ let frame2 = 0;
5990
+ const read = () => {
5991
+ frame2 = 0;
5992
+ const list = findZoneList(zone.label);
5993
+ const values = list ? shownToggles(list).map((button) => button.getAttribute("aria-expanded") === "true") : [];
5994
+ const closed = values.includes(false), open = values.includes(true);
5995
+ setState((prev) => prev.closed === closed && prev.open === open ? prev : { closed, open });
5996
+ };
5997
+ read();
5998
+ const observer = new MutationObserver(() => {
5999
+ if (!frame2) frame2 = requestAnimationFrame(read);
6000
+ });
6001
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["aria-expanded", FOLDED] });
6002
+ return () => {
6003
+ observer.disconnect();
6004
+ cancelAnimationFrame(frame2);
6005
+ };
6006
+ }, [zone.label, enabled]);
6007
+ return state;
6008
+ }
6009
+ function ZoneControls({ zone, editor, contentType, userId, actions, extra, Menu: Menu3 }) {
4668
6010
  const t = useMessages();
4669
- const shown = Boolean(zone.count && (editor.showOpenAll || editor.showCloseAll || tools));
4670
- const anchor = useLabelAnchor(zone, shown);
4671
- if (!shown || !anchor) return null;
6011
+ const toggleShown = Boolean(zone.count && (editor.showOpenAll || editor.showCloseAll));
6012
+ const items2 = zoneMenuItems(zone, actions);
6013
+ const selecting = actions?.selection?.zone === zone.name;
6014
+ const anchor = useZoneAnchor(zone, toggleShown || Boolean(extra) || items2.length > 0 || selecting);
6015
+ const rows = useRowStates(zone, toggleShown && Boolean(anchor));
6016
+ if (!anchor) return null;
6017
+ const toggle = toggleShown && accordionToggle(rows.closed, rows.open, editor);
4672
6018
  const apply = (open) => {
4673
6019
  const list = findZoneList(zone.label);
4674
- if (list) setAll(list, open, import_react_dom3.unstable_batchedUpdates);
6020
+ if (list) setAll(list, open, import_react_dom4.unstable_batchedUpdates);
4675
6021
  writeMemory(
4676
6022
  storage2(),
4677
6023
  memoryKey({ base: memoryBase(), userId, contentType, zone: zone.name }),
4678
6024
  open ? "open" : "closed"
4679
6025
  );
4680
6026
  };
4681
- return (0, import_react_dom3.createPortal)(
4682
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { gap: 1, "data-testid": `block-accordion-controls-${zone.name}`, children: [
4683
- editor.showOpenAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "expand", label: t.openAll, onClick: () => apply(true) }),
4684
- editor.showCloseAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Tool, { icon: "collapse", label: t.closeAll, onClick: () => apply(false) }),
4685
- tools
4686
- ] }),
6027
+ return (0, import_react_dom4.createPortal)(
6028
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system2.Flex, { gap: 2, alignItems: "center", wrap: "wrap", "data-testid": `block-accordion-controls-${zone.name}`, children: selecting ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SelectionBar, { zone, actions }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6029
+ toggle && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6030
+ import_design_system2.Button,
6031
+ {
6032
+ size: "S",
6033
+ variant: "tertiary",
6034
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: toggle.action === "open" ? "expand" : "collapse", size: 14 }),
6035
+ "aria-expanded": !rows.closed,
6036
+ disabled: toggle.disabled,
6037
+ onClick: () => apply(toggle.action === "open"),
6038
+ "data-testid": `zone-toggle-${zone.name}`,
6039
+ children: toggle.action === "open" ? t.expandAll : t.collapseAll
6040
+ }
6041
+ ),
6042
+ extra,
6043
+ items2.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Menu3, { label: t.moreActions, testid: `zone-more-${zone.name}`, items: items2 })
6044
+ ] }) }),
4687
6045
  anchor
4688
6046
  );
4689
6047
  }
@@ -4694,13 +6052,15 @@ function Gallery({
4694
6052
  contentType,
4695
6053
  userId,
4696
6054
  catalog,
6055
+ zoneTools = null,
6056
+ Menu: Menu3,
4697
6057
  ...props
4698
6058
  }) {
4699
6059
  useInitialAccordions({ zones, editor, docKey, contentType, userId });
4700
6060
  const actions = useRowActions({ zones, components: props.components, catalog, form: props.form });
4701
- React4.useEffect(() => stopAll, [docKey]);
4702
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 3, children: [
4703
- editor.showRowThumbnails !== false && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
6061
+ React5.useEffect(() => stopAll, [docKey]);
6062
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
6063
+ editor.showRowThumbnails !== false && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4704
6064
  RowPreviews,
4705
6065
  {
4706
6066
  zones,
@@ -4709,19 +6069,29 @@ function Gallery({
4709
6069
  Modal: props.Modal
4710
6070
  }
4711
6071
  ),
4712
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RowActions, { zones, actions, Modal: props.Modal }),
4713
- zones.map((zone) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_design_system2.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
4714
- zones.length > 1 && !zone.full && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Typography, { variant: "sigma", textColor: "neutral600", tag: "h3", children: zone.label }),
4715
- !zone.full && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneGallery, { zone, contentType, locale: String(docKey || "").split(":").pop(), ...props }),
4716
- zone.count === 0 && actions?.clip && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_design_system2.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneRowTools, { zone, actions }) }),
4717
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
6072
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RowActions, { zones, actions, Modal: props.Modal }),
6073
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6074
+ GroupRows,
6075
+ {
6076
+ zones,
6077
+ form: props.form,
6078
+ groups: catalog?.groups || null,
6079
+ docKey,
6080
+ labelOf: (row) => catalog?.components?.[row?.__component]?.label || props.components?.[row?.__component]?.info?.displayName || row?.__component || ""
6081
+ }
6082
+ ),
6083
+ zones.map((zone, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(React5.Fragment, { children: [
6084
+ !zone.full && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ZoneGallery, { zone, contentType, locale: String(docKey || "").split(":").pop(), ...props }),
6085
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
4718
6086
  ZoneControls,
4719
6087
  {
4720
6088
  zone,
4721
6089
  editor,
4722
6090
  contentType,
4723
6091
  userId,
4724
- tools: actions && actions.editor.clipboard !== false && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ZoneRowTools, { zone, actions })
6092
+ actions,
6093
+ extra: index === 0 ? zoneTools : null,
6094
+ Menu: Menu3
4725
6095
  }
4726
6096
  )
4727
6097
  ] }, zone.name))
@@ -4729,24 +6099,24 @@ function Gallery({
4729
6099
  }
4730
6100
 
4731
6101
  // admin/Settings.tsx
4732
- var React5 = __toESM(require("react"));
6102
+ var React6 = __toESM(require("react"));
4733
6103
  var import_design_system3 = require("@strapi/design-system");
4734
- var import_styled_components4 = __toESM(require("styled-components"));
4735
- var import_jsx_runtime6 = require("react/jsx-runtime");
6104
+ var import_styled_components5 = __toESM(require("styled-components"));
6105
+ var import_jsx_runtime7 = require("react/jsx-runtime");
4736
6106
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
4737
- var Grid = import_styled_components4.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
4738
- var Card2 = import_styled_components4.default.div`
6107
+ var Grid = import_styled_components5.default.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
6108
+ var Card2 = import_styled_components5.default.div`
4739
6109
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
4740
6110
  border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral0};
4741
6111
  `;
4742
- var Bar = import_styled_components4.default.div`
6112
+ var Bar = import_styled_components5.default.div`
4743
6113
  position: fixed; top: 0; z-index: 4; padding: 12px 32px;
4744
6114
  background: ${({ theme }) => theme.colors.neutral100}; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};
4745
6115
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
4746
6116
  `;
4747
6117
  function useMainRect(anchor) {
4748
- const [rect, setRect] = React5.useState({ left: 0, width: 0 });
4749
- React5.useEffect(() => {
6118
+ const [rect, setRect] = React6.useState({ left: 0, width: 0 });
6119
+ React6.useEffect(() => {
4750
6120
  const read = () => {
4751
6121
  let host = document.getElementById("main-content");
4752
6122
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
@@ -4759,15 +6129,15 @@ function useMainRect(anchor) {
4759
6129
  });
4760
6130
  return rect;
4761
6131
  }
4762
- var Swatches = import_styled_components4.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
4763
- var Label = import_styled_components4.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
6132
+ var Swatches = import_styled_components5.default.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
6133
+ var Label = import_styled_components5.default.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
4764
6134
  function ColorField({ name, label, value, onChange, disabled }) {
4765
6135
  const valid = COLOR2.test(value);
4766
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label, { children: [
4767
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
4768
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, children: [
4769
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
4770
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6136
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Label, { children: [
6137
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
6138
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 2, children: [
6139
+ /* @__PURE__ */ (0, import_jsx_runtime7.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" } }),
6140
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4771
6141
  "input",
4772
6142
  {
4773
6143
  name,
@@ -4783,14 +6153,14 @@ function ColorField({ name, label, value, onChange, disabled }) {
4783
6153
  ] });
4784
6154
  }
4785
6155
  function TagsField({ name, label, hint, value, onChange, disabled }) {
4786
- const [text, setText] = React5.useState(value.join(", "));
4787
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label, { children: [
4788
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
4789
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { name, value: text, disabled, onChange: (e) => {
6156
+ const [text, setText] = React6.useState(value.join(", "));
6157
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Label, { children: [
6158
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
6159
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { name, value: text, disabled, onChange: (e) => {
4790
6160
  setText(e.target.value);
4791
6161
  onChange([...new Set(e.target.value.split(",").map((tag) => tag.replace(/[<>]/g, "").trim().slice(0, 24)).filter(Boolean))].slice(0, 10));
4792
6162
  }, style: { padding: "6px 8px", border: "1px solid #dcdce4", borderRadius: 4, fontSize: 13 } }),
4793
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: hint })
6163
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: hint })
4794
6164
  ] });
4795
6165
  }
4796
6166
  var FIELD_UID = /^(plugin|global)::[\w.-]+$/;
@@ -4798,11 +6168,11 @@ var LAZY_MAX = 20;
4798
6168
  var parseUids = (text) => [...new Set(text.split(/[\s,]+/).filter(Boolean))];
4799
6169
  var badUids = (uids = []) => uids.length > LAZY_MAX || uids.some((uid) => !FIELD_UID.test(uid));
4800
6170
  function UidListField({ TextField: TextField2, value, onChange, ...props }) {
4801
- const [text, setText] = React5.useState(value.join(", "));
4802
- React5.useEffect(() => {
6171
+ const [text, setText] = React6.useState(value.join(", "));
6172
+ React6.useEffect(() => {
4803
6173
  if (parseUids(text).join() !== value.join()) setText(value.join(", "));
4804
6174
  }, [value.join()]);
4805
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TextField2, { ...props, value: text, onChange: (v) => {
6175
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextField2, { ...props, value: text, onChange: (v) => {
4806
6176
  setText(v);
4807
6177
  onChange(parseUids(v));
4808
6178
  } });
@@ -4812,73 +6182,148 @@ var SIDEBAR_MAX = 12;
4812
6182
  var ITEM_LABEL = /^[^<>]{1,40}$/;
4813
6183
  var badItem = (item) => !ITEM_LABEL.test(String(item.label || "").trim()) || !item.fields?.length;
4814
6184
  var SYSTEM_FIELDS2 = ["createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
4815
- var Item = import_styled_components4.default.div`
6185
+ var Item = import_styled_components5.default.div`
4816
6186
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
4817
6187
  border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral100};
4818
6188
  `;
4819
- var Checks = import_styled_components4.default.fieldset`
6189
+ var Checks = import_styled_components5.default.fieldset`
4820
6190
  display: flex; flex-wrap: wrap; gap: 4px 16px; border: 0; padding: 0; margin: 0; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800};
4821
6191
  legend { font-size: 12px; font-weight: 600; margin-bottom: 4px; }
4822
6192
  label { display: inline-flex; align-items: center; gap: 6px; }
4823
6193
  `;
6194
+ var TOOLBAR = ["modes", "history", "devices", "status", "actions"];
6195
+ var DEVICE_NAMES = ["fit", "mobile", "tablet", "desktop"];
6196
+ var DEVICE_LABEL = /^[^<>]{1,24}$/;
6197
+ var badDevices = (list = []) => list.length < 1 || list.length > 8 || list.some((item) => typeof item !== "string" && (!DEVICE_LABEL.test(String(item.label || "").trim()) || !(Number.isInteger(item.width) && item.width >= 240 && item.width <= 3840))) || new Set(list.map((item) => typeof item === "string" ? item : item.width)).size !== list.length;
6198
+ var Row = import_styled_components5.default.div` display: flex; align-items: center; gap: 8px; min-height: 36px; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800}; `;
6199
+ function PaneEditor({ id, toolbar, devices, set: set2, t, disabled, TextField: TextField2 }) {
6200
+ const move = (list, index, by) => {
6201
+ const next = [...list];
6202
+ [next[index], next[index + by]] = [next[index + by], next[index]];
6203
+ return next;
6204
+ };
6205
+ const arrows = (list, index, key) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
6206
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index < 0 || index === 0, onClick: () => set2(key, move(list, index, -1)) }),
6207
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index < 0 || index === list.length - 1, onClick: () => set2(key, move(list, index, 1)) })
6208
+ ] });
6209
+ const check = (list, item, key) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6210
+ "input",
6211
+ {
6212
+ type: "checkbox",
6213
+ name: `${id}-${key}-${item}`,
6214
+ checked: list.includes(item),
6215
+ disabled,
6216
+ onChange: (e) => set2(key, e.target.checked ? [...list, item] : list.filter((entry) => entry !== item))
6217
+ }
6218
+ );
6219
+ const width = (index, patch) => set2("previewDevices", devices.map((item, i) => i === index ? { ...item, ...patch } : item));
6220
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 3, "data-testid": `pane-editor-${id}`, children: [
6221
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.paneHelp }),
6222
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { children: [...toolbar, ...TOOLBAR.filter((item) => !toolbar.includes(item))].map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Row, { "data-testid": `${id}-toolbar-${item}`, children: [
6223
+ arrows(toolbar, toolbar.indexOf(item), "previewToolbar"),
6224
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
6225
+ check(toolbar, item, "previewToolbar"),
6226
+ t.toolbar[item]
6227
+ ] })
6228
+ ] }, item)) }),
6229
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "delta", tag: "h3", children: t.paneDevices }),
6230
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.paneDevicesHelp }),
6231
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { children: [...devices, ...DEVICE_NAMES.filter((item) => !devices.includes(item))].map((item) => {
6232
+ const index = devices.indexOf(item);
6233
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Row, { "data-testid": `${id}-device-${typeof item === "string" ? item : index}`, children: [
6234
+ arrows(devices, index, "previewDevices"),
6235
+ typeof item === "string" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
6236
+ check(devices, item, "previewDevices"),
6237
+ t.device[item]
6238
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
6239
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { flex: "1 1 160px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextField2, { name: `${id}-device-label-${index}`, label: t.paneWidthLabel, value: item.label, disabled, onChange: (v) => width(index, { label: v }) }) }),
6240
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { width: 140 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6241
+ TextField2,
6242
+ {
6243
+ name: `${id}-device-width-${index}`,
6244
+ label: t.paneWidth,
6245
+ value: Number.isFinite(item.width) ? String(item.width) : "",
6246
+ disabled,
6247
+ onChange: (v) => width(index, { width: /^\d{1,4}$/.test(v.trim()) ? Number(v.trim()) : NaN })
6248
+ }
6249
+ ) }),
6250
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "close", label: t.paneRemoveWidth, disabled, onClick: () => set2("previewDevices", devices.filter((_, i) => i !== index)) })
6251
+ ] })
6252
+ ] }, typeof item === "string" ? item : `px-${index}`);
6253
+ }) }),
6254
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6255
+ import_design_system3.Button,
6256
+ {
6257
+ variant: "secondary",
6258
+ size: "S",
6259
+ disabled: disabled || devices.length >= 8,
6260
+ "data-testid": `${id}-add-width`,
6261
+ onClick: () => set2("previewDevices", [...devices, { label: "", width: 1280 }]),
6262
+ children: t.paneAddWidth
6263
+ }
6264
+ ) }),
6265
+ badDevices(devices) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", variant: "pi", textColor: "danger600", children: t.paneInvalid })
6266
+ ] });
6267
+ }
4824
6268
  var DAYS = (n) => Number.isInteger(n) && n >= 1 && n <= 3650;
4825
- var badRetention = (h) => !h || !DAYS(h.retentionDays) || !DAYS(h.eventDays) || h.eventDays < h.retentionDays || !(Number.isInteger(h.maxSnapshots) && h.maxSnapshots >= 1 && h.maxSnapshots <= 1e3);
4826
- function HistorySettings({ types, history, set, t, disabled, ToggleField: ToggleField2, TextField: TextField2 }) {
6269
+ var badRetention = (h) => !h || !DAYS(h.retentionDays) || !DAYS(h.eventDays) || !DAYS(h.trashDays) || h.eventDays < h.retentionDays || !(Number.isInteger(h.maxSnapshots) && h.maxSnapshots >= 1 && h.maxSnapshots <= 1e3);
6270
+ function HistorySettings({ types, history, set: set2, t, disabled, ToggleField: ToggleField2, TextField: TextField2 }) {
4827
6271
  const all = history.contentTypes === "all";
4828
6272
  const list = all ? [] : history.contentTypes;
4829
- const number = (key) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6273
+ const number = (key) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { minWidth: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4830
6274
  TextField2,
4831
6275
  {
4832
6276
  name: `history-${key}`,
4833
- label: t[{ retentionDays: "historyRetention", maxSnapshots: "historyMax", eventDays: "historyEventDays" }[key]],
6277
+ label: t[{ retentionDays: "historyRetention", maxSnapshots: "historyMax", eventDays: "historyEventDays", trashDays: "trashDays" }[key]],
4834
6278
  value: Number.isFinite(history[key]) ? String(history[key]) : "",
4835
6279
  disabled,
4836
- onChange: (v) => set(key, /^\d{1,5}$/.test(v.trim()) ? Number(v.trim()) : NaN)
6280
+ onChange: (v) => set2(key, /^\d{1,5}$/.test(v.trim()) ? Number(v.trim()) : NaN)
4837
6281
  }
4838
6282
  ) });
4839
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
4840
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.historySettings }),
4841
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
4842
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set("enabled", v) }),
4843
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
4844
- !all && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Checks, { disabled: disabled || !history.enabled, children: [
4845
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: t.historyTypes }),
4846
- types.map((type) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4847
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6283
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
6284
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.historySettings }),
6285
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
6286
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set2("enabled", v) }),
6287
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set2("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
6288
+ !all && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Checks, { disabled: disabled || !history.enabled, children: [
6289
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: t.historyTypes }),
6290
+ types.map((type) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
6291
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4848
6292
  "input",
4849
6293
  {
4850
6294
  type: "checkbox",
4851
6295
  name: `history-type-${type.uid}`,
4852
6296
  checked: list.includes(type.uid),
4853
- onChange: (e) => set("contentTypes", e.target.checked ? [...list, type.uid] : list.filter((uid) => uid !== type.uid))
6297
+ onChange: (e) => set2("contentTypes", e.target.checked ? [...list, type.uid] : list.filter((uid) => uid !== type.uid))
4854
6298
  }
4855
6299
  ),
4856
6300
  type.displayName
4857
6301
  ] }, type.uid))
4858
6302
  ] }),
4859
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
6303
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
4860
6304
  number("retentionDays"),
4861
6305
  number("maxSnapshots"),
4862
- number("eventDays")
6306
+ number("eventDays"),
6307
+ number("trashDays")
4863
6308
  ] }),
4864
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : t.historyRetentionHelp })
6309
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : `${t.historyRetentionHelp} ${t.trashDaysHelp}` })
4865
6310
  ] }) });
4866
6311
  }
4867
- function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
4868
- const items = entry.sidebar || [];
4869
- const save = (next) => set("sidebar", next.length ? next : void 0, void 0);
4870
- const edit = (index, patch) => save(items.map((item, i) => i === index ? { ...item, ...patch } : item));
6312
+ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
6313
+ const items2 = entry.sidebar || [];
6314
+ const save = (next) => set2("sidebar", next.length ? next : void 0, void 0);
6315
+ const edit = (index, patch) => save(items2.map((item, i) => i === index ? { ...item, ...patch } : item));
4871
6316
  const move = (index, by) => {
4872
- const next = [...items];
6317
+ const next = [...items2];
4873
6318
  [next[index], next[index + by]] = [next[index + by], next[index]];
4874
6319
  save(next);
4875
6320
  };
4876
6321
  const fields = (type.attributes || []).filter((attr) => !SYSTEM_FIELDS2.includes(attr.name));
4877
6322
  const id = (name, index) => `sidebar-${name}-${type.uid}${index === void 0 ? "" : `-${index}`}`;
4878
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
4879
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
4880
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
4881
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { maxWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6323
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
6324
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
6325
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
6326
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { maxWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4882
6327
  SelectField2,
4883
6328
  {
4884
6329
  name: id("position"),
@@ -4886,24 +6331,24 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4886
6331
  value: entry.sidebarPosition || "left",
4887
6332
  disabled,
4888
6333
  options: ["left", "right", "bottom"].map((value) => ({ value, label: t.positions[value] })),
4889
- onChange: (v) => set("sidebarPosition", v, "left")
6334
+ onChange: (v) => set2("sidebarPosition", v, "left")
4890
6335
  }
4891
6336
  ) }),
4892
- items.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Item, { "data-testid": id("item", index), children: [
4893
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
4894
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
4895
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 180 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6337
+ items2.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Item, { "data-testid": id("item", index), children: [
6338
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
6339
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
6340
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { minWidth: 180 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4896
6341
  SelectField2,
4897
6342
  {
4898
6343
  name: id("icon", index),
4899
6344
  label: t.sidebarIcon,
4900
6345
  value: item.icon || "none",
4901
6346
  disabled,
4902
- options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { name: value, size: 16 }) }))],
6347
+ options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { name: value, size: 16 }) }))],
4903
6348
  onChange: (v) => edit(index, { icon: v === "none" ? void 0 : v })
4904
6349
  }
4905
6350
  ) }),
4906
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 160 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6351
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { minWidth: 160 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4907
6352
  SelectField2,
4908
6353
  {
4909
6354
  name: id("open", index),
@@ -4914,16 +6359,16 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4914
6359
  onChange: (v) => edit(index, { open: v })
4915
6360
  }
4916
6361
  ) }),
4917
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 1, paddingBottom: 1, children: [
4918
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
4919
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items.length - 1, onClick: () => move(index, 1) }),
4920
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items.filter((_, i) => i !== index)) })
6362
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 1, paddingBottom: 1, children: [
6363
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
6364
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items2.length - 1, onClick: () => move(index, 1) }),
6365
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items2.filter((_, i) => i !== index)) })
4921
6366
  ] })
4922
6367
  ] }),
4923
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Checks, { disabled, children: [
4924
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("legend", { children: t.sidebarFields }),
4925
- fields.map((attr) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("label", { children: [
4926
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6368
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Checks, { disabled, children: [
6369
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("legend", { children: t.sidebarFields }),
6370
+ fields.map((attr) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { children: [
6371
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4927
6372
  "input",
4928
6373
  {
4929
6374
  type: "checkbox",
@@ -4935,21 +6380,21 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4935
6380
  attr.name
4936
6381
  ] }, attr.name))
4937
6382
  ] }),
4938
- badItem(item) && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
6383
+ badItem(item) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
4939
6384
  ] }, index)),
4940
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, alignItems: "center", children: [
4941
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6385
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 2, alignItems: "center", children: [
6386
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
4942
6387
  import_design_system3.Button,
4943
6388
  {
4944
6389
  variant: "secondary",
4945
6390
  size: "S",
4946
- disabled: disabled || items.length >= SIDEBAR_MAX,
6391
+ disabled: disabled || items2.length >= SIDEBAR_MAX,
4947
6392
  "data-testid": id("add"),
4948
- onClick: () => save([...items, { label: "", open: "drawer", fields: [] }]),
6393
+ onClick: () => save([...items2, { label: "", open: "drawer", fields: [] }]),
4949
6394
  children: t.sidebarAdd
4950
6395
  }
4951
6396
  ),
4952
- items.length >= SIDEBAR_MAX && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
6397
+ items2.length >= SIDEBAR_MAX && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
4953
6398
  ] })
4954
6399
  ] });
4955
6400
  }
@@ -4958,18 +6403,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
4958
6403
  const t = useMessages();
4959
6404
  const { get, put, del } = useClient();
4960
6405
  const { canRead, canUpdate, isLoading } = usePermissions2();
4961
- const [data, setData] = React5.useState(null);
4962
- const [catalog, setCatalog] = React5.useState(null);
4963
- const [settings, setSettings] = React5.useState(null);
4964
- const [media, setMedia] = React5.useState({});
4965
- const [sources, setSources] = React5.useState({});
4966
- const [dirty, setDirty] = React5.useState(false);
4967
- const [saving, setSaving] = React5.useState(false);
4968
- const [status, setStatus] = React5.useState("");
4969
- const [failed, setFailed] = React5.useState(false);
4970
- const [filter, setFilter] = React5.useState("");
4971
- const [picking, setPicking] = React5.useState(null);
4972
- React5.useEffect(() => {
6406
+ const [data, setData] = React6.useState(null);
6407
+ const [catalog, setCatalog] = React6.useState(null);
6408
+ const [settings, setSettings] = React6.useState(null);
6409
+ const [media, setMedia] = React6.useState({});
6410
+ const [sources, setSources] = React6.useState({});
6411
+ const [dirty, setDirty] = React6.useState(false);
6412
+ const [saving, setSaving] = React6.useState(false);
6413
+ const [status, setStatus] = React6.useState("");
6414
+ const [failed, setFailed] = React6.useState(false);
6415
+ const [filter, setFilter] = React6.useState("");
6416
+ const [picking, setPicking] = React6.useState(null);
6417
+ React6.useEffect(() => {
4973
6418
  if (!canRead || isLoading) return;
4974
6419
  let active = true;
4975
6420
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -4994,7 +6439,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
4994
6439
  const badSidebar = settings && Object.values(settings.contentTypes || {}).some((entry) => (entry.sidebar || []).some(badItem));
4995
6440
  const badLazy = settings && badUids(settings.editor.lazyFields);
4996
6441
  const badHistory = settings && data?.historyTypes && badRetention(settings.history);
4997
- const invalid = badColor || badSidebar || badLazy || badHistory;
6442
+ const badPane = settings && [settings.editor, ...Object.values(settings.contentTypes || {})].some((entry) => entry.previewDevices && badDevices(entry.previewDevices));
6443
+ const invalid = badColor || badSidebar || badLazy || badHistory || badPane;
4998
6444
  const save = async () => {
4999
6445
  if (!settings || invalid || !canUpdate) return;
5000
6446
  setSaving(true);
@@ -5046,36 +6492,36 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5046
6492
  return index === 0 && manual ? t.manual : t.automatic;
5047
6493
  };
5048
6494
  const ready = !isLoading && canRead && !failed && settings && catalog;
5049
- const header = React5.useRef(null);
5050
- const [floating, setFloating] = React5.useState(false);
6495
+ const header = React6.useRef(null);
6496
+ const [floating, setFloating] = React6.useState(false);
5051
6497
  const main = useMainRect(header);
5052
- React5.useEffect(() => {
6498
+ React6.useEffect(() => {
5053
6499
  const el = header.current;
5054
6500
  if (!el || typeof IntersectionObserver === "undefined") return;
5055
6501
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
5056
6502
  observer.observe(el);
5057
6503
  return () => observer.disconnect();
5058
6504
  }, [ready]);
5059
- const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
5060
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
5061
- !suffix && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
5062
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
6505
+ const controls = (suffix) => ready && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 3, alignItems: "center", wrap: "wrap", children: [
6506
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
6507
+ !suffix && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Button, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
6508
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Button, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
5063
6509
  ] });
5064
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
5065
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
5066
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
6510
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 8, background: "neutral100", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 5, children: [
6511
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { ref: header, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
6512
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
5067
6513
  controls("")
5068
6514
  ] }) }),
5069
- floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
5070
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
6515
+ floating && main.width > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
6516
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "p", children: t.settingsTitle }),
5071
6517
  controls("-floating")
5072
6518
  ] }) }),
5073
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { textColor: "neutral600", children: t.settingsIntro }),
5074
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5075
- data.disabled && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
5076
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
5077
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.palette }),
5078
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6519
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { textColor: "neutral600", children: t.settingsIntro }),
6520
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { children: t.loading }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
6521
+ data.disabled && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
6522
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
6523
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.palette }),
6524
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5079
6525
  ColorField,
5080
6526
  {
5081
6527
  name: `palette-${key}`,
@@ -5089,42 +6535,43 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5089
6535
  },
5090
6536
  key
5091
6537
  )) }),
5092
- badColor && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
5093
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
5094
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", gap: 1, children: [
5095
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Wireframe, { template, palette: settings.palette }) }),
5096
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
6538
+ badColor && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.invalidColor }),
6539
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
6540
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", gap: 1, children: [
6541
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Wireframe, { template, palette: settings.palette }) }),
6542
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
5097
6543
  ] }, template)) }),
5098
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
6544
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Flex, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
5099
6545
  s.palette = { ...DEFAULT_PALETTE };
5100
6546
  return s;
5101
6547
  }), children: t.resetPalette }) })
5102
6548
  ] }) }),
5103
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
5104
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.editor }),
5105
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6549
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
6550
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.editor }),
6551
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5106
6552
  s.editor.enabled = v;
5107
6553
  return s;
5108
6554
  }) }),
5109
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
5110
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6555
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
6556
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5111
6557
  s.editor.showOpenAll = v;
5112
6558
  return s;
5113
6559
  }) }),
5114
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6560
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5115
6561
  s.editor.showCloseAll = v;
5116
6562
  return s;
5117
6563
  }) }),
5118
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6564
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.toggleHelp }),
6565
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5119
6566
  s.editor.showRowThumbnails = v;
5120
6567
  return s;
5121
6568
  }) }),
5122
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6569
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5123
6570
  s.editor.friendlyLabels = v;
5124
6571
  return s;
5125
6572
  }) }),
5126
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
5127
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6573
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
6574
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5128
6575
  SelectField2,
5129
6576
  {
5130
6577
  name: "editor-initialState",
@@ -5138,8 +6585,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5138
6585
  })
5139
6586
  }
5140
6587
  ),
5141
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
5142
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6588
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
6589
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5143
6590
  TextField2,
5144
6591
  {
5145
6592
  name: "editor-blockPreviewUrl",
@@ -5153,9 +6600,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5153
6600
  })
5154
6601
  }
5155
6602
  ),
5156
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
5157
- previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5158
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6603
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
6604
+ previewSupported ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
6605
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5159
6606
  TextField2,
5160
6607
  {
5161
6608
  name: "editor-previewUrl",
@@ -5169,8 +6616,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5169
6616
  })
5170
6617
  }
5171
6618
  ),
5172
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
5173
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6619
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
6620
+ !editor.previewUrl && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "warning700", "data-testid": "preview-url-empty", children: t.previewUrlEmpty }),
6621
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5174
6622
  SelectField2,
5175
6623
  {
5176
6624
  name: "editor-previewMode",
@@ -5184,12 +6632,28 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5184
6632
  })
5185
6633
  }
5186
6634
  ),
5187
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
5188
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6635
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
6636
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "delta", tag: "h3", children: t.paneTitle }),
6637
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6638
+ PaneEditor,
6639
+ {
6640
+ id: "editor",
6641
+ toolbar: editor.previewToolbar || TOOLBAR,
6642
+ devices: editor.previewDevices || DEVICE_NAMES,
6643
+ t,
6644
+ disabled: !canUpdate || saving,
6645
+ TextField: TextField2,
6646
+ set: (key, value) => update((s) => {
6647
+ s.editor[key] = value;
6648
+ return s;
6649
+ })
6650
+ }
6651
+ ),
6652
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5189
6653
  s.editor.lazyEditors = v;
5190
6654
  return s;
5191
6655
  }) }),
5192
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6656
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5193
6657
  UidListField,
5194
6658
  {
5195
6659
  TextField: TextField2,
@@ -5204,31 +6668,31 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5204
6668
  })
5205
6669
  }
5206
6670
  ),
5207
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
5208
- data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
5209
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6671
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
6672
+ data.blockPreviewAvailable && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
6673
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5210
6674
  s.editor.blockPreviewInForm = v;
5211
6675
  return s;
5212
6676
  }) }),
5213
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
6677
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
5214
6678
  ] })
5215
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
6679
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
5216
6680
  ] }) }),
5217
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
5218
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
5219
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6681
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
6682
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
6683
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5220
6684
  s.editor.confirmDelete = v;
5221
6685
  return s;
5222
6686
  }) }),
5223
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6687
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5224
6688
  s.editor.duplicate = v;
5225
6689
  return s;
5226
6690
  }) }),
5227
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6691
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5228
6692
  s.editor.clipboard = v;
5229
6693
  return s;
5230
6694
  }) }),
5231
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6695
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5232
6696
  SelectField2,
5233
6697
  {
5234
6698
  name: "editor-hiddenBlocks",
@@ -5242,9 +6706,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5242
6706
  })
5243
6707
  }
5244
6708
  ),
5245
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
6709
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
5246
6710
  ] }) }),
5247
- data.historyTypes && settings.history && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6711
+ data.historyTypes && settings.history && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5248
6712
  HistorySettings,
5249
6713
  {
5250
6714
  types: data.historyTypes,
@@ -5259,12 +6723,12 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5259
6723
  })
5260
6724
  }
5261
6725
  ),
5262
- (data.contentTypes || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
5263
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.contentTypes }),
5264
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
6726
+ (data.contentTypes || []).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
6727
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.contentTypes }),
6728
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
5265
6729
  data.contentTypes.map((type) => {
5266
6730
  const entry = settings.contentTypes?.[type.uid] || {};
5267
- const set = (key, value, fallback) => update((s) => {
6731
+ const set2 = (key, value, fallback) => update((s) => {
5268
6732
  const next = { ...s.contentTypes?.[type.uid] || {} };
5269
6733
  if (value === fallback) delete next[key];
5270
6734
  else next[key] = value;
@@ -5273,19 +6737,19 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5273
6737
  else delete s.contentTypes[type.uid];
5274
6738
  return s;
5275
6739
  });
5276
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
5277
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
5278
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 220 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6740
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
6741
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
6742
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { minWidth: 220 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5279
6743
  ToggleField2,
5280
6744
  {
5281
6745
  name: `type-enabled-${type.uid}`,
5282
6746
  label: type.displayName,
5283
6747
  value: entry.enabled !== false,
5284
6748
  disabled: !canUpdate || saving,
5285
- onChange: (v) => set("enabled", v, true)
6749
+ onChange: (v) => set2("enabled", v, true)
5286
6750
  }
5287
6751
  ) }),
5288
- previewSupported && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { style: { minWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6752
+ previewSupported && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { style: { minWidth: 240 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5289
6753
  SelectField2,
5290
6754
  {
5291
6755
  name: `type-mode-${type.uid}`,
@@ -5293,25 +6757,52 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5293
6757
  value: entry.previewMode || "default",
5294
6758
  disabled: !canUpdate || saving || entry.enabled === false,
5295
6759
  options: [{ value: "default", label: t.f("modeDefault", { mode: t.modes[editor.previewMode || "form"] }) }, ...["form", "split", "preview"].map((value) => ({ value, label: t.modes[value] }))],
5296
- onChange: (v) => set("previewMode", v, "default")
6760
+ onChange: (v) => set2("previewMode", v, "default")
5297
6761
  }
5298
6762
  ) })
5299
6763
  ] }),
5300
- previewSupported && entry.enabled !== false && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SidebarEditor, { type, entry, set, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 })
6764
+ previewSupported && entry.enabled !== false && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SidebarEditor, { type, entry, set: set2, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 }),
6765
+ previewSupported && entry.enabled !== false && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, children: [
6766
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6767
+ ToggleField2,
6768
+ {
6769
+ name: `type-pane-${type.uid}`,
6770
+ label: t.f("paneTypeOverride", { name: type.displayName }),
6771
+ value: Boolean(entry.previewToolbar || entry.previewDevices),
6772
+ disabled: !canUpdate || saving,
6773
+ onChange: (v) => {
6774
+ set2("previewToolbar", v ? [...editor.previewToolbar || TOOLBAR] : void 0, void 0);
6775
+ set2("previewDevices", v ? structuredClone(editor.previewDevices || DEVICE_NAMES) : void 0, void 0);
6776
+ }
6777
+ }
6778
+ ),
6779
+ (entry.previewToolbar || entry.previewDevices) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
6780
+ PaneEditor,
6781
+ {
6782
+ id: `type-${type.uid}`,
6783
+ toolbar: entry.previewToolbar || editor.previewToolbar || TOOLBAR,
6784
+ devices: entry.previewDevices || editor.previewDevices || DEVICE_NAMES,
6785
+ t,
6786
+ disabled: !canUpdate || saving,
6787
+ TextField: TextField2,
6788
+ set: (key, value) => set2(key, value, void 0)
6789
+ }
6790
+ )
6791
+ ] })
5301
6792
  ] }, type.uid);
5302
6793
  }),
5303
- badSidebar && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
6794
+ badSidebar && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
5304
6795
  ] }) }),
5305
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
5306
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.components }),
5307
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
5308
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
5309
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
6796
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Box, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
6797
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "beta", tag: "h2", children: t.components }),
6798
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Searchbar, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
6799
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
6800
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Grid, { "data-testid": "components-grid", children: components.map((component) => {
5310
6801
  const entry = settings.components[component.uid] || {};
5311
6802
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
5312
6803
  const candidates = candidatesFor(component.uid, meta, catalog);
5313
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
5314
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6804
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Card2, { "data-testid": `settings-${component.uid}`, children: [
6805
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5315
6806
  Thumb,
5316
6807
  {
5317
6808
  candidates,
@@ -5322,23 +6813,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5322
6813
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
5323
6814
  }
5324
6815
  ),
5325
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
5326
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
5327
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: [
6816
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
6817
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
6818
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Typography, { variant: "pi", textColor: "neutral600", children: [
5328
6819
  component.uid,
5329
6820
  " \xB7 ",
5330
6821
  component.category
5331
6822
  ] }),
5332
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
6823
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Typography, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
5333
6824
  t.source,
5334
6825
  ": ",
5335
6826
  sourceOf(component.uid, Boolean(meta.manualImage)),
5336
6827
  meta.manualName ? ` (${meta.manualName})` : ""
5337
6828
  ] }),
5338
- meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
5339
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_design_system3.Flex, { gap: 2, wrap: "wrap", children: [
5340
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
5341
- entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
6829
+ meta.manualMissing && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Typography, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
6830
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_design_system3.Flex, { gap: 2, wrap: "wrap", children: [
6831
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Button, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
6832
+ entry.mediaId && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system3.Button, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
5342
6833
  update((s) => {
5343
6834
  delete s.components[component.uid]?.mediaId;
5344
6835
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -5351,7 +6842,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5351
6842
  });
5352
6843
  }, children: t.useAutomatic })
5353
6844
  ] }),
5354
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6845
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5355
6846
  SelectField2,
5356
6847
  {
5357
6848
  name: `template-${component.uid}`,
@@ -5365,7 +6856,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5365
6856
  })
5366
6857
  }
5367
6858
  ),
5368
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6859
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5369
6860
  SelectField2,
5370
6861
  {
5371
6862
  name: `typology-${component.uid}`,
@@ -5376,7 +6867,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5376
6867
  onChange: (v) => setComponent(component.uid, "typology", v === "auto" ? void 0 : v)
5377
6868
  }
5378
6869
  ),
5379
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
6870
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
5380
6871
  TagsField,
5381
6872
  {
5382
6873
  name: `tags-${component.uid}`,
@@ -5391,7 +6882,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5391
6882
  ] }, component.uid);
5392
6883
  }) })
5393
6884
  ] }) }),
5394
- picking && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
6885
+ picking && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
5395
6886
  const uid = picking;
5396
6887
  setPicking(null);
5397
6888
  if (!asset?.id) return;
@@ -5420,16 +6911,41 @@ function register(app, Component2, to) {
5420
6911
  }
5421
6912
 
5422
6913
  // admin/catalog.ts
5423
- var React6 = __toESM(require("react"));
6914
+ var React8 = __toESM(require("react"));
6915
+
6916
+ // admin/FieldHelp.tsx
6917
+ var React7 = __toESM(require("react"));
6918
+ var import_styled_components6 = __toESM(require("styled-components"));
6919
+ var import_design_system4 = require("@strapi/design-system");
6920
+ var import_jsx_runtime8 = require("react/jsx-runtime");
6921
+ var HelpButton = import_styled_components6.default.button`
6922
+ display: inline-flex; padding: 0; border: 0; border-radius: 50%; background: none; cursor: help; color: inherit;
6923
+ &:hover, &:focus-visible { color: ${({ theme }) => theme.colors.primary600}; }
6924
+ &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
6925
+ `;
6926
+ function FieldHelp({ text, previous, title }) {
6927
+ const m = useMessages();
6928
+ const kept = React7.isValidElement(previous) && previous.props.title ? React7.cloneElement(previous, { title }) : previous;
6929
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_design_system4.Flex, { gap: 1, alignItems: "center", children: [
6930
+ kept,
6931
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system4.Tooltip, { label: text, style: { maxWidth: 320 }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(HelpButton, { type: "button", "aria-label": m.fieldHelp, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { name: "info", size: 14 }) }) })
6932
+ ] });
6933
+ }
6934
+ var helpAction = (text, previous) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(FieldHelp, { text, previous, title: React7.isValidElement(previous) && previous.props.title || { id: "blockscene.fieldHelp" } });
6935
+
6936
+ // admin/catalog.ts
5424
6937
  var cached = null;
5425
6938
  var pending = null;
5426
- var load = (get) => get("/blockscene/catalog").then(({ data }) => {
6939
+ var flight = null;
6940
+ var load = (get) => flight || (flight = get("/blockscene/catalog").then(({ data }) => {
5427
6941
  cached = data;
5428
6942
  return data;
5429
- });
6943
+ }).finally(() => {
6944
+ flight = null;
6945
+ }));
5430
6946
  function useCatalog(get) {
5431
- const [catalog, setCatalog] = React6.useState(null);
5432
- React6.useEffect(() => {
6947
+ const [catalog, setCatalog] = React8.useState(null);
6948
+ React8.useEffect(() => {
5433
6949
  let active = true;
5434
6950
  load(get).then((data) => {
5435
6951
  if (active) setCatalog(data);
@@ -5456,7 +6972,7 @@ var labelsHook = (get, relabel, drop) => (args) => {
5456
6972
  pending = null;
5457
6973
  }));
5458
6974
  const trimmed = drop(args.layout, cached ? cached.hiddenAttribute : "bsHidden");
5459
- const layout = cached ? relabel(trimmed, cached, adminLocale()) : trimmed;
6975
+ const layout = cached ? relabel(trimmed, cached, adminLocale(), helpAction) : trimmed;
5460
6976
  return layout === args.layout ? args : { ...args, layout };
5461
6977
  } catch (error) {
5462
6978
  console.error("[blockscene] field labels skipped after an error:", error);
@@ -5465,14 +6981,14 @@ var labelsHook = (get, relabel, drop) => (args) => {
5465
6981
  };
5466
6982
 
5467
6983
  // admin/Guard.tsx
5468
- var React7 = __toESM(require("react"));
5469
- var import_design_system4 = require("@strapi/design-system");
5470
- var import_jsx_runtime7 = require("react/jsx-runtime");
6984
+ var React9 = __toESM(require("react"));
6985
+ var import_design_system5 = require("@strapi/design-system");
6986
+ var import_jsx_runtime9 = require("react/jsx-runtime");
5471
6987
  var Notice = () => {
5472
6988
  const t = useMessages();
5473
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system4.Box, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_design_system4.Typography, { variant: "pi", textColor: "warning700", role: "alert", children: t.crashed }) });
6989
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_design_system5.Box, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_design_system5.Typography, { variant: "pi", textColor: "warning700", role: "alert", children: t.crashed }) });
5474
6990
  };
5475
- var Guard = class extends React7.Component {
6991
+ var Guard = class extends React9.Component {
5476
6992
  constructor() {
5477
6993
  super(...arguments);
5478
6994
  __publicField(this, "state", { failed: false });
@@ -5484,25 +7000,29 @@ var Guard = class extends React7.Component {
5484
7000
  console.error("[blockscene] disabled for this view after an error:", error);
5485
7001
  }
5486
7002
  render() {
5487
- return this.state.failed ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Notice, {}) : this.props.children;
7003
+ return this.state.failed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Notice, {}) : this.props.children;
5488
7004
  }
5489
7005
  };
5490
7006
 
5491
7007
  // admin/strapi4.tsx
5492
- var import_jsx_runtime8 = require("react/jsx-runtime");
7008
+ var import_jsx_runtime10 = require("react/jsx-runtime");
5493
7009
  function Modal({ open, onOpenChange, trigger, title, children, width = "80vw" }) {
5494
- const id = React8.useId();
5495
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
7010
+ const id = React10.useId();
7011
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
5496
7012
  trigger,
5497
- open && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_design_system5.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
5498
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.Typography, { id, variant: "beta", children: title }) }),
5499
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.ModalBody, { children })
7013
+ open && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_design_system6.ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
7014
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.Typography, { id, variant: "beta", children: title }) }),
7015
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.ModalBody, { children })
5500
7016
  ] })
5501
7017
  ] });
5502
7018
  }
7019
+ var Menu2 = ({ label, testid, items: items2 }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { "data-testid": testid, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.SimpleMenu, { variant: "tertiary", size: "S", "aria-label": label, title: label, endIcon: null, label: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "more", size: 16 }), children: items2.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.MenuItem, { onClick: item.onSelect, "data-testid": item.testid, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_design_system6.Flex, { as: "span", gap: 2, alignItems: "center", children: [
7020
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: item.icon, size: 16 }),
7021
+ item.label
7022
+ ] }) }, item.testid)) }) });
5503
7023
  function useRowForm(c, components) {
5504
7024
  const toggleNotification = (0, import_helper_plugin.useNotification)();
5505
- const latest = React8.useRef(c.modifiedData);
7025
+ const latest = React10.useRef(c.modifiedData);
5506
7026
  latest.current = c.modifiedData;
5507
7027
  if (typeof c.onChange !== "function") return null;
5508
7028
  return {
@@ -5510,6 +7030,7 @@ function useRowForm(c, components) {
5510
7030
  locale: c.initialData?.locale || void 0,
5511
7031
  rows: (zone) => Array.isArray(latest.current?.[zone]) ? latest.current[zone] : [],
5512
7032
  setRows: (zone, rows) => c.onChange({ target: { name: zone, value: rows } }),
7033
+ errorRows: (zone) => errorRows(c.formErrors, zone),
5513
7034
  keys: (rows, _at, n) => integerKeys(rows, n),
5514
7035
  notify: (type, message) => toggleNotification({ type, message }),
5515
7036
  prepare: async (rows) => rows.map((row) => cloneRow(row, components))
@@ -5554,7 +7075,7 @@ function Picker() {
5554
7075
  };
5555
7076
  if (!catalog?.editor?.enabled || catalog.contentTypes?.[c.slug]?.enabled === false) return null;
5556
7077
  const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
5557
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
7078
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { hidden: true, "data-blockscene-editor": "", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5558
7079
  Gallery,
5559
7080
  {
5560
7081
  zones,
@@ -5569,13 +7090,14 @@ function Picker() {
5569
7090
  docKey,
5570
7091
  contentType: c.slug,
5571
7092
  userId: import_helper_plugin.auth.getUserInfo?.()?.id,
5572
- form
7093
+ form,
7094
+ Menu: Menu2
5573
7095
  }
5574
- );
7096
+ ) });
5575
7097
  }
5576
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_design_system5.Flex, { gap: 3, children: [
5577
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5578
- import_design_system5.Switch,
7098
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_design_system6.Flex, { gap: 3, children: [
7099
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
7100
+ import_design_system6.Switch,
5579
7101
  {
5580
7102
  name,
5581
7103
  "aria-label": label,
@@ -5584,9 +7106,9 @@ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ *
5584
7106
  onChange: () => onChange(!value)
5585
7107
  }
5586
7108
  ),
5587
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.Typography, { children: label })
7109
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.Typography, { children: label })
5588
7110
  ] });
5589
- var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
7111
+ var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
5590
7112
  var SelectField = ({
5591
7113
  name,
5592
7114
  label,
@@ -5594,15 +7116,15 @@ var SelectField = ({
5594
7116
  onChange,
5595
7117
  disabled,
5596
7118
  options
5597
- }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
5598
- import_design_system5.SingleSelect,
7119
+ }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
7120
+ import_design_system6.SingleSelect,
5599
7121
  {
5600
7122
  name,
5601
7123
  label,
5602
7124
  value,
5603
7125
  disabled,
5604
7126
  onChange: (v) => onChange(String(v)),
5605
- children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_design_system5.SingleSelectOption, { value: o.value, children: o.label }, o.value))
7127
+ children: options.map((o) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_design_system6.SingleSelectOption, { value: o.value, children: o.label }, o.value))
5606
7128
  }
5607
7129
  );
5608
7130
  function MediaPicker({ onClose, onSelect }) {
@@ -5612,7 +7134,7 @@ function MediaPicker({ onClose, onSelect }) {
5612
7134
  onClose();
5613
7135
  return null;
5614
7136
  }
5615
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
7137
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5616
7138
  Dialog,
5617
7139
  {
5618
7140
  onClose,
@@ -5629,7 +7151,7 @@ function usePermissions() {
5629
7151
  isLoading
5630
7152
  };
5631
7153
  }
5632
- var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
7154
+ var SettingsPage = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
5633
7155
  Settings,
5634
7156
  {
5635
7157
  useClient: import_helper_plugin.useFetchClient,
@@ -5651,7 +7173,7 @@ var strapi4_default = {
5651
7173
  app.registerHook("Admin/CM/pages/EditView/mutate-edit-view-layout", labelsHook(() => (0, import_helper_plugin.getFetchClient)().get, labelEditLayout4, dropField4));
5652
7174
  app.injectContentManagerComponent("editView", "right-links", {
5653
7175
  name: "blockscene",
5654
- Component: () => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Picker, {}) })
7176
+ Component: () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Guard, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Picker, {}) })
5655
7177
  });
5656
7178
  }
5657
7179
  };