@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.mjs CHANGED
@@ -45,7 +45,7 @@ var require_groups = __commonJS({
45
45
  var uidOf = (row) => typeof row?.__component === "string" ? row.__component : "";
46
46
  var isOpener2 = (row, g) => Boolean(g) && Object.prototype.hasOwnProperty.call(g, uidOf(row));
47
47
  var isClose2 = (row, g) => Boolean(g) && Object.values(g).includes(uidOf(row));
48
- var blockKey2 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
48
+ var blockKey3 = (row) => row && row.id != null ? `${row.__component}#${row.id}` : row && row.__temp_key__ != null ? String(row.__temp_key__) : null;
49
49
  function validateGroups3(rows, g) {
50
50
  const errors = [];
51
51
  if (!g || !Array.isArray(rows)) return errors;
@@ -87,8 +87,8 @@ var require_groups = __commonJS({
87
87
  const closed = uidOf(rows[end]) === g[uidOf(row)] && end > i;
88
88
  out.push({
89
89
  type: "group",
90
- key: blockKey2(row),
91
- closeKey: closed ? blockKey2(rows[end]) : null,
90
+ key: blockKey3(row),
91
+ closeKey: closed ? blockKey3(rows[end]) : null,
92
92
  row,
93
93
  index: offset + i,
94
94
  depth,
@@ -97,7 +97,7 @@ var require_groups = __commonJS({
97
97
  i = end + 1;
98
98
  continue;
99
99
  }
100
- out.push({ type: "block", key: blockKey2(row), row, index: offset + i, depth, stray: isClose2(row, g) });
100
+ out.push({ type: "block", key: blockKey3(row), row, index: offset + i, depth, stray: isClose2(row, g) });
101
101
  i++;
102
102
  }
103
103
  return out;
@@ -115,7 +115,7 @@ var require_groups = __commonJS({
115
115
  function moveGroup2(rows, key, direction, g) {
116
116
  if (!g) return null;
117
117
  const ranges = topLevelRanges2(rows, g);
118
- const at = ranges.findIndex(([s]) => blockKey2(rows[s]) === String(key));
118
+ const at = ranges.findIndex(([s]) => blockKey3(rows[s]) === String(key));
119
119
  const to = at + (direction === "up" ? -1 : 1);
120
120
  if (at < 0 || to < 0 || to >= ranges.length) return null;
121
121
  const [a, b] = direction === "up" ? [ranges[to], ranges[at]] : [ranges[at], ranges[to]];
@@ -123,24 +123,26 @@ var require_groups = __commonJS({
123
123
  }
124
124
  function removeGroup2(rows, key, g) {
125
125
  if (!g) return null;
126
- const start = rows.findIndex((row) => blockKey2(row) === String(key));
126
+ const start = rows.findIndex((row) => blockKey3(row) === String(key));
127
127
  if (start < 0 || !isOpener2(rows[start], g)) return null;
128
128
  const [, end] = groupRange3(rows, start, g);
129
129
  return [...rows.slice(0, start), ...rows.slice(end + 1)];
130
130
  }
131
- module.exports = { safeGroups: safeGroups2, validateGroups: validateGroups3, groupRange: groupRange3, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey2, isOpener: isOpener2, isClose: isClose2 };
131
+ module.exports = { safeGroups: safeGroups2, validateGroups: validateGroups3, groupRange: groupRange3, groupRows: groupRows2, topLevelRanges: topLevelRanges2, moveGroup: moveGroup2, removeGroup: removeGroup2, blockKey: blockKey3, isOpener: isOpener2, isClose: isClose2 };
132
132
  }
133
133
  });
134
134
 
135
135
  // admin/strapi4.tsx
136
- import * as React8 from "react";
136
+ import * as React10 from "react";
137
137
  import {
138
+ MenuItem,
139
+ SimpleMenu,
138
140
  ModalLayout,
139
141
  ModalHeader,
140
142
  ModalBody,
141
143
  Typography as Typography5,
142
144
  Switch,
143
- Flex as Flex4,
145
+ Flex as Flex5,
144
146
  SingleSelect,
145
147
  SingleSelectOption,
146
148
  TextInput
@@ -156,8 +158,8 @@ import {
156
158
  } from "@strapi/helper-plugin";
157
159
 
158
160
  // admin/Gallery.tsx
159
- import * as React4 from "react";
160
- import { createPortal as createPortal3, unstable_batchedUpdates } from "react-dom";
161
+ import * as React5 from "react";
162
+ import { createPortal as createPortal4, unstable_batchedUpdates } from "react-dom";
161
163
  import {
162
164
  Box,
163
165
  Button as Button2,
@@ -165,7 +167,7 @@ import {
165
167
  Searchbar,
166
168
  Typography as Typography2
167
169
  } from "@strapi/design-system";
168
- import styled3 from "styled-components";
170
+ import styled4 from "styled-components";
169
171
 
170
172
  // admin/model.mjs
171
173
  import { generateNKeysBetween } from "fractional-indexing";
@@ -301,9 +303,9 @@ function groupEntries(entries) {
301
303
  const map = /* @__PURE__ */ new Map();
302
304
  for (const entry of entries)
303
305
  map.set(entry.typology, [...map.get(entry.typology) || [], entry]);
304
- return [...map.entries()].map(([typology, items]) => ({
306
+ return [...map.entries()].map(([typology, items2]) => ({
305
307
  typology,
306
- entries: items
308
+ entries: items2
307
309
  }));
308
310
  }
309
311
  function memoryKey({ base = "", userId, contentType, zone }) {
@@ -353,19 +355,23 @@ function fieldText(fields, owner, name, label, locale, on) {
353
355
  const out = {};
354
356
  const text = localized(entry.label, locale) ?? (on && label === name ? humanize(name) : void 0);
355
357
  if (text !== void 0) out.label = text;
356
- for (const key of ["description", "placeholder"]) {
358
+ for (const key of ["description", "placeholder", "help"]) {
357
359
  const value = localized(entry[key], locale);
358
360
  if (value !== void 0) out[key] = value;
359
361
  }
360
362
  return Object.keys(out).length ? out : null;
361
363
  }
362
364
  var labelsOff = (catalog) => !catalog?.editor?.enabled || !catalog.editor.friendlyLabels && !Object.keys(catalog.fields || {}).length;
365
+ var withHelp = (description, help) => description ? `${description} ${help}` : help;
363
366
  function labelEditLayout4(layout, catalog, locale) {
364
367
  const uid = layout?.contentType?.uid;
365
368
  if (labelsOff(catalog) || !uid || catalog.contentTypes?.[uid]?.enabled === false) return layout;
366
369
  const fix = (owner) => (field) => {
367
370
  const text = field?.metadatas && fieldText(catalog.fields, owner, field.name, field.metadatas.label, locale, catalog.editor.friendlyLabels);
368
- return text ? { ...field, metadatas: { ...field.metadatas, ...text } } : field;
371
+ if (!text) return field;
372
+ const { help, ...rest } = text;
373
+ const metadatas = { ...field.metadatas, ...rest };
374
+ return { ...field, metadatas: help === void 0 ? metadatas : { ...metadatas, description: withHelp(metadatas.description, help) } };
369
375
  };
370
376
  const rows = (target, owner) => Array.isArray(target?.layouts?.edit) ? { ...target, layouts: { ...target.layouts, edit: target.layouts.edit.map((row) => row.map(fix(owner))) } } : target;
371
377
  return {
@@ -472,7 +478,7 @@ function useStageSize(el) {
472
478
  return size;
473
479
  }
474
480
  var frameStyle = (device, stage) => {
475
- const width = DEVICES[device];
481
+ const width = typeof device === "number" ? device : DEVICES[device];
476
482
  if (!width || !stage.width) return { left: 0, width: "100%", height: "100%" };
477
483
  const scale = Math.min(1, stage.width / width);
478
484
  return { left: Math.max(0, (stage.width - width * scale) / 2), width, height: stage.height / scale, transform: `scale(${scale})` };
@@ -498,6 +504,8 @@ function findZoneList(label, root = document) {
498
504
  function toggles(list) {
499
505
  return [...list.querySelectorAll(":scope > li")].map((item) => item.querySelector("button[aria-expanded]")).filter(Boolean);
500
506
  }
507
+ var FOLDED = "data-blockscene-folded";
508
+ var shownToggles = (list) => toggles(list).filter((button) => !button.closest(`li[${FOLDED}]`));
501
509
  function planRows(rects, view, margin = 0) {
502
510
  const now = [], later = [];
503
511
  const gap = (r) => Math.max(view.top - margin - r.bottom, r.top - view.bottom - margin, 0);
@@ -535,7 +543,7 @@ function setAll(list, open, batch = (run) => run()) {
535
543
  });
536
544
  return buttons.length;
537
545
  };
538
- const rows = [...list.querySelectorAll(":scope > li")].filter(differs);
546
+ const rows = [...list.querySelectorAll(":scope > li")].filter((li) => !li.hasAttribute(FOLDED) && differs(li));
539
547
  if (!rows.length) return 0;
540
548
  const root = scroller(list);
541
549
  const view = () => root ? root.getBoundingClientRect() : { top: 0, bottom: window.innerHeight };
@@ -591,12 +599,16 @@ function setAll(list, open, batch = (run) => run()) {
591
599
  return changed;
592
600
  }
593
601
  function isNativeAddButton(button, zone) {
594
- 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;
602
+ 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;
595
603
  const text = (button.textContent || "").trim();
596
604
  const escape = (value) => String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
597
605
  const names = [...new Set([zone.name, zone.label].filter(Boolean))].map(escape).join("|");
598
606
  return Boolean(text) && new RegExp(`(^|\\s)(${names})$`).test(text);
599
607
  }
608
+ function accordionToggle(closed, open, { showOpenAll, showCloseAll }) {
609
+ const action = showOpenAll && (closed || !showCloseAll) ? "open" : showCloseAll ? "close" : null;
610
+ return action && { action, disabled: action === "open" ? !closed : !open };
611
+ }
600
612
 
601
613
  // admin/wireframes.tsx
602
614
  import { jsx } from "react/jsx-runtime";
@@ -648,7 +660,6 @@ var en_default = {
648
660
  title: "Blockscene",
649
661
  settings: "Gallery",
650
662
  gallery: "Block gallery",
651
- add: "Add block",
652
663
  search: "Search blocks",
653
664
  clear: "Clear search",
654
665
  empty: "No blocks found.",
@@ -658,8 +669,9 @@ var en_default = {
658
669
  failed: "Could not load the catalog. Close and try again.",
659
670
  insertFailed: "Could not create this component. Use the native picker and report its schema.",
660
671
  example: "Images are examples; appearance depends on your frontend.",
661
- openAll: "Open all blocks",
662
- closeAll: "Close all blocks",
672
+ expandAll: "Expand all",
673
+ collapseAll: "Collapse all",
674
+ moreActions: "More actions",
663
675
  settingsTitle: "Blockscene",
664
676
  settingsIntro: "Gallery thumbnails, wireframe palette and editor preferences. Changes apply the next time the gallery opens; no rebuild is needed.",
665
677
  palette: "Wireframe palette",
@@ -687,8 +699,9 @@ var en_default = {
687
699
  editor: "Editor preferences",
688
700
  enabled: "Blockscene enabled",
689
701
  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.",
690
- showOpenAll: 'Show "Open all blocks"',
691
- showCloseAll: 'Show "Close all blocks"',
702
+ showOpenAll: 'Show "Expand all"',
703
+ showCloseAll: 'Show "Collapse all"',
704
+ 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.",
692
705
  showRowThumbnails: "Show block thumbnails in the rows",
693
706
  initialState: "Initial accordion state",
694
707
  "states.closed": "All closed",
@@ -697,6 +710,7 @@ var en_default = {
697
710
  rememberHelp: "Only the explicit open all / close all buttons update the memory, per user and browser. Opening one block does not.",
698
711
  previewUrl: "Preview route base URL",
699
712
  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).",
713
+ 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.",
700
714
  previewMode: "Initial preview mode",
701
715
  "modes.form": "Fields",
702
716
  "modes.split": "Fields + page",
@@ -715,8 +729,6 @@ var en_default = {
715
729
  resize: "Resize preview pane",
716
730
  resizeHint: "Drag to resize; double-click to reset to half",
717
731
  scrollToHovered: "Scroll to the highlighted block",
718
- 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.",
719
- previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
720
732
  previewFailed: "The preview did not answer within 15 s. If the frontend is still loading it will appear by itself; the form stays usable.",
721
733
  previewLoading: "Loading preview\u2026",
722
734
  retry: "Try again",
@@ -861,8 +873,13 @@ var en_default = {
861
873
  confirmDelete: "Delete block {name}?",
862
874
  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.",
863
875
  delete: "Delete",
864
- selectMode: "Select blocks to copy",
865
- copySelected: "Copy selected ({count})",
876
+ selectBlocks: "Select blocks",
877
+ selectAll: "Select all",
878
+ selectNone: "Select none",
879
+ selectedCount: "{count} selected",
880
+ copy: "Copy",
881
+ copyNothing: "Select at least one block to copy.",
882
+ selectDone: "Done",
866
883
  paste: "Paste {count, plural, one {# block} other {# blocks}}",
867
884
  pasted: "{count, plural, one {# block pasted} other {# blocks pasted}}.",
868
885
  copied: "{count, plural, one {# block copied} other {# blocks copied}}. Paste on any page of this site.",
@@ -925,7 +942,120 @@ var en_default = {
925
942
  historyMax: "Snapshots per document (maximum)",
926
943
  historyEventDays: "Keep the activity (days)",
927
944
  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.",
928
- historyInvalid: "Whole numbers: 1 to 3650 days (the activity kept at least as long as the snapshots) and 1 to 1000 snapshots."
945
+ historyInvalid: "Whole numbers: 1 to 3650 days (the activity kept at least as long as the snapshots) and 1 to 1000 snapshots.",
946
+ fieldHelp: "More information",
947
+ paneTitle: "Page preview toolbar",
948
+ 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.",
949
+ "toolbar.modes": "Editing mode",
950
+ "toolbar.history": "Undo and redo",
951
+ "toolbar.devices": "Page width menu",
952
+ "toolbar.status": "Document status",
953
+ "toolbar.actions": "Save and Publish",
954
+ paneDevices: "Page widths",
955
+ 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.",
956
+ paneAddWidth: "Add a width",
957
+ paneWidthLabel: "Label",
958
+ paneWidth: "Width (px)",
959
+ paneRemoveWidth: "Remove width",
960
+ 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.",
961
+ paneTypeOverride: "Own page preview toolbar for {name}",
962
+ add: "Add block",
963
+ openAll: "Open all blocks",
964
+ closeAll: "Close all blocks",
965
+ 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.",
966
+ previewNoUrl: "No preview URL: set it in Settings, Blockscene, or configure Strapi's native Preview for this content type.",
967
+ selectMode: "Select blocks to copy",
968
+ copySelected: "Copy selected ({count})",
969
+ trashDays: "Keep deleted documents (days)",
970
+ trashDaysHelp: "Deleted documents stay in the trash that many days (fixed when each one is deleted), then the nightly job deletes them.",
971
+ "historyActions.purge": "Deleted forever",
972
+ contentMenu: "Activity and trash",
973
+ contentTitle: "Content activity and trash",
974
+ contentSubtitle: "Changes made through Strapi (admin, API, plugins) to the content types the version history covers.",
975
+ contentOff: "Version history is off: nothing new is recorded or trashed. Turn it on in Settings, Blockscene.",
976
+ contentLoading: "Loading\u2026",
977
+ contentNone: "\u2014",
978
+ contentUntitled: "(untitled)",
979
+ contentGone: "no longer exists",
980
+ contentOpen: "Open",
981
+ contentPrevious: "Previous",
982
+ contentNext: "Next",
983
+ contentPage: "Page {page} of {pages}, {total} in total",
984
+ contentClear: "Clear filters",
985
+ activityTab: "Activity",
986
+ activityPerson: "Person",
987
+ activityAnyone: "Anyone",
988
+ activityType: "Content type",
989
+ activityAnyType: "All content types",
990
+ activityAction: "Action",
991
+ activityAnyAction: "All actions",
992
+ activityFrom: "From",
993
+ activityTo: "To",
994
+ activitySearch: "Title contains",
995
+ activitySearchButton: "Search",
996
+ activityWhen: "When",
997
+ activityDocument: "Document",
998
+ activityWho: "Who",
999
+ activityWhat: "What",
1000
+ activityEmpty: "No activity matches these filters.",
1001
+ activityFailed: "The activity could not be loaded.",
1002
+ activityRestoredFrom: "Back from the trash",
1003
+ trashTab: "Trash",
1004
+ trashShowRestored: "Show restored entries",
1005
+ trashLocales: "Locales",
1006
+ trashDeletedBy: "Deleted by",
1007
+ trashDeletedAt: "Deleted",
1008
+ trashExpires: "Deleted forever",
1009
+ trashExpiresIn: "in {days} days",
1010
+ trashExpiresToday: "tonight",
1011
+ trashRestoredAs: "Restored",
1012
+ trashEmpty: "The trash is empty.",
1013
+ trashFailed: "The trash could not be loaded.",
1014
+ trashPreview: "Preview",
1015
+ trashRestore: "Restore",
1016
+ trashDelete: "Delete forever",
1017
+ trashDeleteTitle: "Delete forever",
1018
+ trashDeleteConfirm: "Delete \u201C{title}\u201D from the trash forever? It cannot be restored afterwards. Media files are not deleted.",
1019
+ trashDeleted: "Deleted forever.",
1020
+ trashDeleteFailed: "It could not be deleted.",
1021
+ trashDraft: "draft",
1022
+ trashPublished: "published",
1023
+ trashFields: "Fields",
1024
+ trashBlocks: "Blocks",
1025
+ trashItems: "{count} item(s)",
1026
+ trashIncoming: "{count} link(s) from other documents or blocks were kept.",
1027
+ trashClose: "Close",
1028
+ restoreTitle: "Restore \u201C{title}\u201D",
1029
+ restoreChecking: "Checking what a restore would do\u2026",
1030
+ restoreIntro: "The document comes back as a draft, with its draft content: check it, then publish it again.",
1031
+ restoreNew: "A new document is created (Strapi does not reuse the original id).",
1032
+ restoreInto: "The locales are added back to the existing document.",
1033
+ restoreLocales: "Locales restored: {locales}",
1034
+ restoreBlocked: "It cannot be restored as it is (nothing is written):",
1035
+ restoreWarnings: "It is restored with these differences:",
1036
+ restoreConfirm: "Restore as draft",
1037
+ restoreCancel: "Cancel",
1038
+ restoreDone: "Restored as a draft.",
1039
+ restoreAlready: "This entry was already restored.",
1040
+ restoreFailed: "The restore failed: nothing was written.",
1041
+ restoreOpen: "Open the restored document",
1042
+ "report.typeGone": "The content type no longer exists.",
1043
+ "report.localeExists": "The document has the {locale} locale again.",
1044
+ "report.unique": "\u201C{value}\u201D is already used in {field} ({locale}) by another document.",
1045
+ "report.singleExists": "This single type has a document again.",
1046
+ "report.nothing": "Nothing left to restore: none of its locales is configured any more.",
1047
+ "report.restored": "Already restored.",
1048
+ "report.published": "A published version existed ({locales}): it is kept in the trash entry, the draft is what comes back.",
1049
+ "report.localeRemoved": "The {locale} locale is no longer configured: skipped.",
1050
+ "report.required": "Required fields are empty ({locale}): {fields}. Fill them before publishing.",
1051
+ "report.fieldsRemoved": "Fields the schema no longer has, left out ({locale}): {fields}.",
1052
+ "report.media": "{count} media file(s) no longer exist, left empty ({locale}).",
1053
+ "report.relations": "{count} related document(s) no longer exist, left out ({locale}).",
1054
+ "report.blocks": "{count} block(s) whose component the zone no longer allows, left out ({locale}).",
1055
+ "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).",
1056
+ groupCollapse: "Collapse group {label}",
1057
+ groupExpand: "Expand group {label}",
1058
+ groupBlocks: "{count, plural, one {# block} other {# blocks}}"
929
1059
  };
930
1060
 
931
1061
  // admin/translations/pt-BR.json
@@ -933,7 +1063,6 @@ var pt_BR_default = {
933
1063
  title: "Blockscene",
934
1064
  settings: "Galeria",
935
1065
  gallery: "Galeria de blocos",
936
- add: "Adicionar bloco",
937
1066
  search: "Buscar blocos",
938
1067
  clear: "Limpar busca",
939
1068
  empty: "Nenhum bloco encontrado.",
@@ -943,8 +1072,9 @@ var pt_BR_default = {
943
1072
  failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
944
1073
  insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
945
1074
  example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
946
- openAll: "Abrir todos os blocos",
947
- closeAll: "Fechar todos os blocos",
1075
+ expandAll: "Expandir tudo",
1076
+ collapseAll: "Recolher tudo",
1077
+ moreActions: "Mais a\xE7\xF5es",
948
1078
  settingsTitle: "Blockscene",
949
1079
  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.",
950
1080
  palette: "Paleta dos wireframes",
@@ -972,8 +1102,9 @@ var pt_BR_default = {
972
1102
  editor: "Prefer\xEAncias do editor",
973
1103
  enabled: "Blockscene ligado",
974
1104
  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.",
975
- showOpenAll: 'Mostrar "Abrir todos os blocos"',
976
- showCloseAll: 'Mostrar "Fechar todos os blocos"',
1105
+ showOpenAll: 'Mostrar "Expandir tudo"',
1106
+ showCloseAll: 'Mostrar "Recolher tudo"',
1107
+ 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.",
977
1108
  showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
978
1109
  initialState: "Estado inicial dos accordions",
979
1110
  "states.closed": "Todos fechados",
@@ -982,6 +1113,7 @@ var pt_BR_default = {
982
1113
  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.",
983
1114
  previewUrl: "URL base da rota de preview",
984
1115
  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).",
1116
+ 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.",
985
1117
  previewMode: "Modo inicial da preview",
986
1118
  "modes.form": "Campos",
987
1119
  "modes.split": "Campos + p\xE1gina",
@@ -1000,8 +1132,6 @@ var pt_BR_default = {
1000
1132
  resize: "Redimensionar painel de preview",
1001
1133
  resizeHint: "Arraste para redimensionar; clique duplo volta \xE0 metade",
1002
1134
  scrollToHovered: "Rolar at\xE9 o bloco destacado",
1003
- 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.",
1004
- previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
1005
1135
  previewFailed: "A preview n\xE3o respondeu em 15 s. Se o frontend ainda estiver carregando, ela aparece sozinha; o formul\xE1rio continua utiliz\xE1vel.",
1006
1136
  previewLoading: "Carregando preview\u2026",
1007
1137
  retry: "Tentar novamente",
@@ -1146,8 +1276,13 @@ var pt_BR_default = {
1146
1276
  confirmDelete: "Excluir o bloco {name}?",
1147
1277
  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.",
1148
1278
  delete: "Excluir",
1149
- selectMode: "Selecionar blocos para copiar",
1150
- copySelected: "Copiar selecionados ({count})",
1279
+ selectBlocks: "Selecionar blocos",
1280
+ selectAll: "Selecionar todos",
1281
+ selectNone: "Desmarcar todos",
1282
+ selectedCount: "{count, plural, one {# selecionado} other {# selecionados}}",
1283
+ copy: "Copiar",
1284
+ copyNothing: "Selecione ao menos um bloco para copiar.",
1285
+ selectDone: "Concluir",
1151
1286
  paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
1152
1287
  pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
1153
1288
  copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
@@ -1210,7 +1345,120 @@ var pt_BR_default = {
1210
1345
  historyMax: "Snapshots por documento (m\xE1ximo)",
1211
1346
  historyEventDays: "Manter a atividade (dias)",
1212
1347
  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.",
1213
- historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots."
1348
+ historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots.",
1349
+ fieldHelp: "Mais informa\xE7\xF5es",
1350
+ paneTitle: "Barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
1351
+ 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.",
1352
+ "toolbar.modes": "Modo de edi\xE7\xE3o",
1353
+ "toolbar.history": "Desfazer e refazer",
1354
+ "toolbar.devices": "Menu de largura da p\xE1gina",
1355
+ "toolbar.status": "Status do documento",
1356
+ "toolbar.actions": "Salvar e Publicar",
1357
+ paneDevices: "Larguras da p\xE1gina",
1358
+ 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.",
1359
+ paneAddWidth: "Adicionar largura",
1360
+ paneWidthLabel: "Nome",
1361
+ paneWidth: "Largura (px)",
1362
+ paneRemoveWidth: "Remover largura",
1363
+ 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.",
1364
+ paneTypeOverride: "Barra pr\xF3pria da pr\xE9-visualiza\xE7\xE3o para {name}",
1365
+ add: "Adicionar bloco",
1366
+ openAll: "Abrir todos os blocos",
1367
+ closeAll: "Fechar todos os blocos",
1368
+ 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.",
1369
+ previewNoUrl: "Sem URL de preview: defina em Configura\xE7\xF5es, Blockscene, ou configure a Preview nativa do Strapi para este tipo de conte\xFAdo.",
1370
+ selectMode: "Selecionar blocos para copiar",
1371
+ copySelected: "Copiar selecionados ({count})",
1372
+ trashDays: "Manter documentos exclu\xEDdos (dias)",
1373
+ 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.",
1374
+ "historyActions.purge": "Exclu\xEDdo definitivamente",
1375
+ contentMenu: "Atividade e lixeira",
1376
+ contentTitle: "Atividade de conte\xFAdo e lixeira",
1377
+ contentSubtitle: "Altera\xE7\xF5es feitas pelo Strapi (admin, API, plugins) nos tipos de conte\xFAdo cobertos pelo hist\xF3rico de vers\xF5es.",
1378
+ 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.",
1379
+ contentLoading: "Carregando\u2026",
1380
+ contentNone: "\u2014",
1381
+ contentUntitled: "(sem t\xEDtulo)",
1382
+ contentGone: "n\xE3o existe mais",
1383
+ contentOpen: "Abrir",
1384
+ contentPrevious: "Anterior",
1385
+ contentNext: "Pr\xF3xima",
1386
+ contentPage: "P\xE1gina {page} de {pages}, {total} no total",
1387
+ contentClear: "Limpar filtros",
1388
+ activityTab: "Atividade",
1389
+ activityPerson: "Pessoa",
1390
+ activityAnyone: "Qualquer pessoa",
1391
+ activityType: "Tipo de conte\xFAdo",
1392
+ activityAnyType: "Todos os tipos de conte\xFAdo",
1393
+ activityAction: "A\xE7\xE3o",
1394
+ activityAnyAction: "Todas as a\xE7\xF5es",
1395
+ activityFrom: "De",
1396
+ activityTo: "At\xE9",
1397
+ activitySearch: "T\xEDtulo cont\xE9m",
1398
+ activitySearchButton: "Buscar",
1399
+ activityWhen: "Quando",
1400
+ activityDocument: "Documento",
1401
+ activityWho: "Quem",
1402
+ activityWhat: "O qu\xEA",
1403
+ activityEmpty: "Nenhuma atividade corresponde a esses filtros.",
1404
+ activityFailed: "N\xE3o foi poss\xEDvel carregar a atividade.",
1405
+ activityRestoredFrom: "Voltou da lixeira",
1406
+ trashTab: "Lixeira",
1407
+ trashShowRestored: "Mostrar itens restaurados",
1408
+ trashLocales: "Idiomas",
1409
+ trashDeletedBy: "Exclu\xEDdo por",
1410
+ trashDeletedAt: "Exclu\xEDdo",
1411
+ trashExpires: "Exclus\xE3o definitiva",
1412
+ trashExpiresIn: "em {days} dias",
1413
+ trashExpiresToday: "esta noite",
1414
+ trashRestoredAs: "Restaurado",
1415
+ trashEmpty: "A lixeira est\xE1 vazia.",
1416
+ trashFailed: "N\xE3o foi poss\xEDvel carregar a lixeira.",
1417
+ trashPreview: "Visualizar",
1418
+ trashRestore: "Restaurar",
1419
+ trashDelete: "Excluir definitivamente",
1420
+ trashDeleteTitle: "Excluir definitivamente",
1421
+ 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.",
1422
+ trashDeleted: "Exclu\xEDdo definitivamente.",
1423
+ trashDeleteFailed: "N\xE3o foi poss\xEDvel excluir.",
1424
+ trashDraft: "rascunho",
1425
+ trashPublished: "publicado",
1426
+ trashFields: "Campos",
1427
+ trashBlocks: "Blocos",
1428
+ trashItems: "{count} item(ns)",
1429
+ trashIncoming: "{count} v\xEDnculo(s) de outros documentos ou blocos foram guardados.",
1430
+ trashClose: "Fechar",
1431
+ restoreTitle: "Restaurar \u201C{title}\u201D",
1432
+ restoreChecking: "Verificando o que a restaura\xE7\xE3o faria\u2026",
1433
+ restoreIntro: "O documento volta como rascunho, com o conte\xFAdo do rascunho: confira e publique de novo.",
1434
+ restoreNew: "Um novo documento \xE9 criado (o Strapi n\xE3o reaproveita o id original).",
1435
+ restoreInto: "Os idiomas voltam para o documento que j\xE1 existe.",
1436
+ restoreLocales: "Idiomas restaurados: {locales}",
1437
+ restoreBlocked: "N\xE3o \xE9 poss\xEDvel restaurar como est\xE1 (nada \xE9 gravado):",
1438
+ restoreWarnings: "Ele \xE9 restaurado com estas diferen\xE7as:",
1439
+ restoreConfirm: "Restaurar como rascunho",
1440
+ restoreCancel: "Cancelar",
1441
+ restoreDone: "Restaurado como rascunho.",
1442
+ restoreAlready: "Este item j\xE1 foi restaurado.",
1443
+ restoreFailed: "A restaura\xE7\xE3o falhou: nada foi gravado.",
1444
+ restoreOpen: "Abrir o documento restaurado",
1445
+ "report.typeGone": "O tipo de conte\xFAdo n\xE3o existe mais.",
1446
+ "report.localeExists": "O documento j\xE1 tem o idioma {locale} de novo.",
1447
+ "report.unique": "\u201C{value}\u201D j\xE1 \xE9 usado em {field} ({locale}) por outro documento.",
1448
+ "report.singleExists": "Este tipo \xFAnico j\xE1 tem um documento de novo.",
1449
+ "report.nothing": "N\xE3o h\xE1 nada para restaurar: nenhum dos idiomas est\xE1 mais configurado.",
1450
+ "report.restored": "J\xE1 restaurado.",
1451
+ "report.published": "Havia uma vers\xE3o publicada ({locales}): ela fica guardada no item da lixeira; o que volta \xE9 o rascunho.",
1452
+ "report.localeRemoved": "O idioma {locale} n\xE3o est\xE1 mais configurado: ignorado.",
1453
+ "report.required": "Campos obrigat\xF3rios vazios ({locale}): {fields}. Preencha antes de publicar.",
1454
+ "report.fieldsRemoved": "Campos que o schema n\xE3o tem mais, deixados de fora ({locale}): {fields}.",
1455
+ "report.media": "{count} arquivo(s) de m\xEDdia n\xE3o existem mais, deixados vazios ({locale}).",
1456
+ "report.relations": "{count} documento(s) relacionados n\xE3o existem mais, deixados de fora ({locale}).",
1457
+ "report.blocks": "{count} bloco(s) cujo componente a zona n\xE3o permite mais, deixados de fora ({locale}).",
1458
+ "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).",
1459
+ groupCollapse: "Recolher grupo {label}",
1460
+ groupExpand: "Expandir grupo {label}",
1461
+ groupBlocks: "{count, plural, one {# bloco} other {# blocos}}"
1214
1462
  };
1215
1463
 
1216
1464
  // admin/translations/pt.json
@@ -1218,7 +1466,6 @@ var pt_default = {
1218
1466
  title: "Blockscene",
1219
1467
  settings: "Galeria",
1220
1468
  gallery: "Galeria de blocos",
1221
- add: "Adicionar bloco",
1222
1469
  search: "Pesquisar blocos",
1223
1470
  clear: "Limpar pesquisa",
1224
1471
  empty: "Nenhum bloco encontrado.",
@@ -1228,8 +1475,9 @@ var pt_default = {
1228
1475
  failed: "N\xE3o foi poss\xEDvel carregar o cat\xE1logo. Feche e tente novamente.",
1229
1476
  insertFailed: "N\xE3o foi poss\xEDvel criar este componente. Use o seletor nativo e informe seu schema.",
1230
1477
  example: "Imagens s\xE3o exemplos; a apar\xEAncia depende do seu frontend.",
1231
- openAll: "Abrir todos os blocos",
1232
- closeAll: "Fechar todos os blocos",
1478
+ expandAll: "Expandir tudo",
1479
+ collapseAll: "Recolher tudo",
1480
+ moreActions: "Mais a\xE7\xF5es",
1233
1481
  settingsTitle: "Blockscene",
1234
1482
  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.",
1235
1483
  palette: "Paleta dos wireframes",
@@ -1257,8 +1505,9 @@ var pt_default = {
1257
1505
  editor: "Prefer\xEAncias do editor",
1258
1506
  enabled: "Blockscene ligado",
1259
1507
  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.",
1260
- showOpenAll: 'Mostrar "Abrir todos os blocos"',
1261
- showCloseAll: 'Mostrar "Fechar todos os blocos"',
1508
+ showOpenAll: 'Mostrar "Expandir tudo"',
1509
+ showCloseAll: 'Mostrar "Recolher tudo"',
1510
+ 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.",
1262
1511
  showRowThumbnails: "Mostrar miniaturas dos blocos nas linhas",
1263
1512
  initialState: "Estado inicial dos accordions",
1264
1513
  "states.closed": "Todos fechados",
@@ -1267,6 +1516,7 @@ var pt_default = {
1267
1516
  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.",
1268
1517
  previewUrl: "URL base da rota de pr\xE9-visualiza\xE7\xE3o",
1269
1518
  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).",
1519
+ 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.",
1270
1520
  previewMode: "Modo inicial da pr\xE9-visualiza\xE7\xE3o",
1271
1521
  "modes.form": "Campos",
1272
1522
  "modes.split": "Campos + p\xE1gina",
@@ -1285,8 +1535,6 @@ var pt_default = {
1285
1535
  resize: "Redimensionar painel de pr\xE9-visualiza\xE7\xE3o",
1286
1536
  resizeHint: "Arraste para redimensionar; duplo clique rep\xF5e a metade",
1287
1537
  scrollToHovered: "Deslocar at\xE9 ao bloco destacado",
1288
- 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.",
1289
- 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.",
1290
1538
  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.",
1291
1539
  previewLoading: "A carregar pr\xE9-visualiza\xE7\xE3o\u2026",
1292
1540
  retry: "Tentar novamente",
@@ -1431,8 +1679,13 @@ var pt_default = {
1431
1679
  confirmDelete: "Eliminar o bloco {name}?",
1432
1680
  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.",
1433
1681
  delete: "Eliminar",
1434
- selectMode: "Selecionar blocos para copiar",
1435
- copySelected: "Copiar selecionados ({count})",
1682
+ selectBlocks: "Selecionar blocos",
1683
+ selectAll: "Selecionar todos",
1684
+ selectNone: "Desmarcar todos",
1685
+ selectedCount: "{count, plural, one {# selecionado} other {# selecionados}}",
1686
+ copy: "Copiar",
1687
+ copyNothing: "Selecione pelo menos um bloco para copiar.",
1688
+ selectDone: "Concluir",
1436
1689
  paste: "Colar {count, plural, one {# bloco} other {# blocos}}",
1437
1690
  pasted: "{count, plural, one {# bloco colado} other {# blocos colados}}.",
1438
1691
  copied: "{count, plural, one {# bloco copiado} other {# blocos copiados}}. Cole em qualquer p\xE1gina deste site.",
@@ -1495,7 +1748,120 @@ var pt_default = {
1495
1748
  historyMax: "Snapshots por documento (m\xE1ximo)",
1496
1749
  historyEventDays: "Manter a atividade (dias)",
1497
1750
  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.",
1498
- historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots."
1751
+ historyInvalid: "N\xFAmeros inteiros: 1 a 3650 dias (a atividade mantida pelo menos tanto quanto os snapshots) e 1 a 1000 snapshots.",
1752
+ fieldHelp: "Mais informa\xE7\xF5es",
1753
+ paneTitle: "Barra da pr\xE9-visualiza\xE7\xE3o da p\xE1gina",
1754
+ 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.",
1755
+ "toolbar.modes": "Modo de edi\xE7\xE3o",
1756
+ "toolbar.history": "Anular e refazer",
1757
+ "toolbar.devices": "Menu de largura da p\xE1gina",
1758
+ "toolbar.status": "Estado do documento",
1759
+ "toolbar.actions": "Guardar e Publicar",
1760
+ paneDevices: "Larguras da p\xE1gina",
1761
+ 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.",
1762
+ paneAddWidth: "Adicionar largura",
1763
+ paneWidthLabel: "Nome",
1764
+ paneWidth: "Largura (px)",
1765
+ paneRemoveWidth: "Remover largura",
1766
+ 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.",
1767
+ paneTypeOverride: "Barra pr\xF3pria da pr\xE9-visualiza\xE7\xE3o para {name}",
1768
+ add: "Adicionar bloco",
1769
+ openAll: "Abrir todos os blocos",
1770
+ closeAll: "Fechar todos os blocos",
1771
+ 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.",
1772
+ 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.",
1773
+ selectMode: "Selecionar blocos para copiar",
1774
+ copySelected: "Copiar selecionados ({count})",
1775
+ trashDays: "Manter documentos eliminados (dias)",
1776
+ 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.",
1777
+ "historyActions.purge": "Eliminado definitivamente",
1778
+ contentMenu: "Atividade e lixo",
1779
+ contentTitle: "Atividade de conte\xFAdo e lixo",
1780
+ contentSubtitle: "Altera\xE7\xF5es feitas atrav\xE9s do Strapi (admin, API, plugins) nos tipos de conte\xFAdo abrangidos pelo hist\xF3rico de vers\xF5es.",
1781
+ 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.",
1782
+ contentLoading: "A carregar\u2026",
1783
+ contentNone: "\u2014",
1784
+ contentUntitled: "(sem t\xEDtulo)",
1785
+ contentGone: "j\xE1 n\xE3o existe",
1786
+ contentOpen: "Abrir",
1787
+ contentPrevious: "Anterior",
1788
+ contentNext: "Seguinte",
1789
+ contentPage: "P\xE1gina {page} de {pages}, {total} no total",
1790
+ contentClear: "Limpar filtros",
1791
+ activityTab: "Atividade",
1792
+ activityPerson: "Pessoa",
1793
+ activityAnyone: "Qualquer pessoa",
1794
+ activityType: "Tipo de conte\xFAdo",
1795
+ activityAnyType: "Todos os tipos de conte\xFAdo",
1796
+ activityAction: "A\xE7\xE3o",
1797
+ activityAnyAction: "Todas as a\xE7\xF5es",
1798
+ activityFrom: "De",
1799
+ activityTo: "At\xE9",
1800
+ activitySearch: "T\xEDtulo cont\xE9m",
1801
+ activitySearchButton: "Pesquisar",
1802
+ activityWhen: "Quando",
1803
+ activityDocument: "Documento",
1804
+ activityWho: "Quem",
1805
+ activityWhat: "O qu\xEA",
1806
+ activityEmpty: "Nenhuma atividade corresponde a estes filtros.",
1807
+ activityFailed: "N\xE3o foi poss\xEDvel carregar a atividade.",
1808
+ activityRestoredFrom: "Recuperado do lixo",
1809
+ trashTab: "Lixo",
1810
+ trashShowRestored: "Mostrar entradas restauradas",
1811
+ trashLocales: "Idiomas",
1812
+ trashDeletedBy: "Eliminado por",
1813
+ trashDeletedAt: "Eliminado",
1814
+ trashExpires: "Elimina\xE7\xE3o definitiva",
1815
+ trashExpiresIn: "daqui a {days} dias",
1816
+ trashExpiresToday: "esta noite",
1817
+ trashRestoredAs: "Restaurado",
1818
+ trashEmpty: "O lixo est\xE1 vazio.",
1819
+ trashFailed: "N\xE3o foi poss\xEDvel carregar o lixo.",
1820
+ trashPreview: "Pr\xE9-visualizar",
1821
+ trashRestore: "Restaurar",
1822
+ trashDelete: "Eliminar definitivamente",
1823
+ trashDeleteTitle: "Eliminar definitivamente",
1824
+ trashDeleteConfirm: "Eliminar \u201C{title}\u201D do lixo definitivamente? Depois n\xE3o poder\xE1 ser restaurado. Os ficheiros multim\xE9dia n\xE3o s\xE3o apagados.",
1825
+ trashDeleted: "Eliminado definitivamente.",
1826
+ trashDeleteFailed: "N\xE3o foi poss\xEDvel eliminar.",
1827
+ trashDraft: "rascunho",
1828
+ trashPublished: "publicado",
1829
+ trashFields: "Campos",
1830
+ trashBlocks: "Blocos",
1831
+ trashItems: "{count} item(ns)",
1832
+ trashIncoming: "{count} liga\xE7\xE3o(\xF5es) de outros documentos ou blocos foram guardadas.",
1833
+ trashClose: "Fechar",
1834
+ restoreTitle: "Restaurar \u201C{title}\u201D",
1835
+ restoreChecking: "A verificar o que o restauro faria\u2026",
1836
+ restoreIntro: "O documento volta como rascunho, com o conte\xFAdo do rascunho: reveja-o e publique-o novamente.",
1837
+ restoreNew: "\xC9 criado um documento novo (o Strapi n\xE3o reutiliza o id original).",
1838
+ restoreInto: "Os idiomas voltam ao documento que j\xE1 existe.",
1839
+ restoreLocales: "Idiomas restaurados: {locales}",
1840
+ restoreBlocked: "N\xE3o pode ser restaurado tal como est\xE1 (nada \xE9 gravado):",
1841
+ restoreWarnings: "\xC9 restaurado com estas diferen\xE7as:",
1842
+ restoreConfirm: "Restaurar como rascunho",
1843
+ restoreCancel: "Cancelar",
1844
+ restoreDone: "Restaurado como rascunho.",
1845
+ restoreAlready: "Esta entrada j\xE1 foi restaurada.",
1846
+ restoreFailed: "O restauro falhou: nada foi gravado.",
1847
+ restoreOpen: "Abrir o documento restaurado",
1848
+ "report.typeGone": "O tipo de conte\xFAdo j\xE1 n\xE3o existe.",
1849
+ "report.localeExists": "O documento voltou a ter o idioma {locale}.",
1850
+ "report.unique": "\u201C{value}\u201D j\xE1 \xE9 usado em {field} ({locale}) por outro documento.",
1851
+ "report.singleExists": "Este tipo \xFAnico voltou a ter um documento.",
1852
+ "report.nothing": "Nada a restaurar: nenhum dos idiomas continua configurado.",
1853
+ "report.restored": "J\xE1 restaurado.",
1854
+ "report.published": "Existia uma vers\xE3o publicada ({locales}): fica guardada na entrada do lixo; o que volta \xE9 o rascunho.",
1855
+ "report.localeRemoved": "O idioma {locale} j\xE1 n\xE3o est\xE1 configurado: ignorado.",
1856
+ "report.required": "Campos obrigat\xF3rios vazios ({locale}): {fields}. Preencha-os antes de publicar.",
1857
+ "report.fieldsRemoved": "Campos que o esquema j\xE1 n\xE3o tem, deixados de fora ({locale}): {fields}.",
1858
+ "report.media": "{count} ficheiro(s) multim\xE9dia j\xE1 n\xE3o existem, deixados vazios ({locale}).",
1859
+ "report.relations": "{count} documento(s) relacionados j\xE1 n\xE3o existem, deixados de fora ({locale}).",
1860
+ "report.blocks": "{count} bloco(s) cujo componente a zona j\xE1 n\xE3o permite, deixados de fora ({locale}).",
1861
+ "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).",
1862
+ groupCollapse: "Recolher grupo {label}",
1863
+ groupExpand: "Expandir grupo {label}",
1864
+ groupBlocks: "{count, plural, one {# bloco} other {# blocos}}"
1499
1865
  };
1500
1866
 
1501
1867
  // admin/translations/fr.json
@@ -1503,7 +1869,6 @@ var fr_default = {
1503
1869
  title: "Blockscene",
1504
1870
  settings: "Galerie",
1505
1871
  gallery: "Galerie de blocs",
1506
- add: "Ajouter un bloc",
1507
1872
  search: "Rechercher des blocs",
1508
1873
  clear: "Effacer la recherche",
1509
1874
  empty: "Aucun bloc trouv\xE9.",
@@ -1513,8 +1878,9 @@ var fr_default = {
1513
1878
  failed: "Impossible de charger le catalogue. Fermez et r\xE9essayez.",
1514
1879
  insertFailed: "Impossible de cr\xE9er ce composant. Utilisez le s\xE9lecteur natif et signalez son sch\xE9ma.",
1515
1880
  example: "Les images sont des exemples ; l'apparence d\xE9pend de votre frontend.",
1516
- openAll: "Ouvrir tous les blocs",
1517
- closeAll: "Fermer tous les blocs",
1881
+ expandAll: "Tout d\xE9plier",
1882
+ collapseAll: "Tout replier",
1883
+ moreActions: "Plus d'actions",
1518
1884
  settingsTitle: "Blockscene",
1519
1885
  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.",
1520
1886
  palette: "Palette des wireframes",
@@ -1542,8 +1908,9 @@ var fr_default = {
1542
1908
  editor: "Pr\xE9f\xE9rences de l'\xE9diteur",
1543
1909
  enabled: "Blockscene activ\xE9",
1544
1910
  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.",
1545
- showOpenAll: "Afficher \xAB Ouvrir tous les blocs \xBB",
1546
- showCloseAll: "Afficher \xAB Fermer tous les blocs \xBB",
1911
+ showOpenAll: "Afficher \xAB Tout d\xE9plier \xBB",
1912
+ showCloseAll: "Afficher \xAB Tout replier \xBB",
1913
+ 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.",
1547
1914
  showRowThumbnails: "Afficher les miniatures des blocs dans les lignes",
1548
1915
  initialState: "\xC9tat initial des accord\xE9ons",
1549
1916
  "states.closed": "Tous ferm\xE9s",
@@ -1552,6 +1919,7 @@ var fr_default = {
1552
1919
  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.",
1553
1920
  previewUrl: "URL de base de la route d'aper\xE7u",
1554
1921
  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).",
1922
+ 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.",
1555
1923
  previewMode: "Mode d'aper\xE7u initial",
1556
1924
  "modes.form": "Champs",
1557
1925
  "modes.split": "Champs + page",
@@ -1570,8 +1938,6 @@ var fr_default = {
1570
1938
  resize: "Redimensionner le panneau d'aper\xE7u",
1571
1939
  resizeHint: "Faites glisser pour redimensionner ; double-clic pour revenir \xE0 la moiti\xE9",
1572
1940
  scrollToHovered: "Faire d\xE9filer jusqu\u2019au bloc en surbrillance",
1573
- 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.",
1574
- 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.",
1575
1941
  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.",
1576
1942
  previewLoading: "Chargement de l'aper\xE7u\u2026",
1577
1943
  retry: "R\xE9essayer",
@@ -1716,8 +2082,13 @@ var fr_default = {
1716
2082
  confirmDelete: "Supprimer le bloc {name} ?",
1717
2083
  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.",
1718
2084
  delete: "Supprimer",
1719
- selectMode: "S\xE9lectionner des blocs \xE0 copier",
1720
- copySelected: "Copier la s\xE9lection ({count})",
2085
+ selectBlocks: "S\xE9lectionner des blocs",
2086
+ selectAll: "Tout s\xE9lectionner",
2087
+ selectNone: "Tout d\xE9s\xE9lectionner",
2088
+ selectedCount: "{count, plural, one {# s\xE9lectionn\xE9} other {# s\xE9lectionn\xE9s}}",
2089
+ copy: "Copier",
2090
+ copyNothing: "S\xE9lectionnez au moins un bloc \xE0 copier.",
2091
+ selectDone: "Termin\xE9",
1721
2092
  paste: "Coller {count, plural, one {# bloc} other {# blocs}}",
1722
2093
  pasted: "{count, plural, one {# bloc coll\xE9} other {# blocs coll\xE9s}}.",
1723
2094
  copied: "{count, plural, one {# bloc copi\xE9} other {# blocs copi\xE9s}}. Collez-les sur n'importe quelle page de ce site.",
@@ -1780,7 +2151,120 @@ var fr_default = {
1780
2151
  historyMax: "Instantan\xE9s par document (maximum)",
1781
2152
  historyEventDays: "Conserver l'activit\xE9 (jours)",
1782
2153
  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.",
1783
- 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."
2154
+ 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.",
2155
+ fieldHelp: "Plus d'informations",
2156
+ paneTitle: "Barre de l'aper\xE7u de page",
2157
+ 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.",
2158
+ "toolbar.modes": "Mode d'\xE9dition",
2159
+ "toolbar.history": "Annuler et r\xE9tablir",
2160
+ "toolbar.devices": "Menu de largeur de page",
2161
+ "toolbar.status": "Statut du document",
2162
+ "toolbar.actions": "Enregistrer et Publier",
2163
+ paneDevices: "Largeurs de page",
2164
+ 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.",
2165
+ paneAddWidth: "Ajouter une largeur",
2166
+ paneWidthLabel: "Libell\xE9",
2167
+ paneWidth: "Largeur (px)",
2168
+ paneRemoveWidth: "Retirer la largeur",
2169
+ 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.",
2170
+ paneTypeOverride: "Barre d'aper\xE7u propre \xE0 {name}",
2171
+ add: "Ajouter un bloc",
2172
+ openAll: "Ouvrir tous les blocs",
2173
+ closeAll: "Fermer tous les blocs",
2174
+ 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.",
2175
+ 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.",
2176
+ selectMode: "S\xE9lectionner des blocs \xE0 copier",
2177
+ copySelected: "Copier la s\xE9lection ({count})",
2178
+ trashDays: "Conserver les documents supprim\xE9s (jours)",
2179
+ 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.",
2180
+ "historyActions.purge": "Supprim\xE9 d\xE9finitivement",
2181
+ contentMenu: "Activit\xE9 et corbeille",
2182
+ contentTitle: "Activit\xE9 du contenu et corbeille",
2183
+ contentSubtitle: "Modifications faites via Strapi (admin, API, plugins) sur les types de contenu couverts par l'historique des versions.",
2184
+ 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.",
2185
+ contentLoading: "Chargement\u2026",
2186
+ contentNone: "\u2014",
2187
+ contentUntitled: "(sans titre)",
2188
+ contentGone: "n'existe plus",
2189
+ contentOpen: "Ouvrir",
2190
+ contentPrevious: "Pr\xE9c\xE9dent",
2191
+ contentNext: "Suivant",
2192
+ contentPage: "Page {page} sur {pages}, {total} au total",
2193
+ contentClear: "Effacer les filtres",
2194
+ activityTab: "Activit\xE9",
2195
+ activityPerson: "Personne",
2196
+ activityAnyone: "Tout le monde",
2197
+ activityType: "Type de contenu",
2198
+ activityAnyType: "Tous les types de contenu",
2199
+ activityAction: "Action",
2200
+ activityAnyAction: "Toutes les actions",
2201
+ activityFrom: "Du",
2202
+ activityTo: "Au",
2203
+ activitySearch: "Le titre contient",
2204
+ activitySearchButton: "Rechercher",
2205
+ activityWhen: "Quand",
2206
+ activityDocument: "Document",
2207
+ activityWho: "Qui",
2208
+ activityWhat: "Quoi",
2209
+ activityEmpty: "Aucune activit\xE9 ne correspond \xE0 ces filtres.",
2210
+ activityFailed: "L'activit\xE9 n'a pas pu \xEAtre charg\xE9e.",
2211
+ activityRestoredFrom: "Sorti de la corbeille",
2212
+ trashTab: "Corbeille",
2213
+ trashShowRestored: "Afficher les entr\xE9es restaur\xE9es",
2214
+ trashLocales: "Langues",
2215
+ trashDeletedBy: "Supprim\xE9 par",
2216
+ trashDeletedAt: "Supprim\xE9",
2217
+ trashExpires: "Suppression d\xE9finitive",
2218
+ trashExpiresIn: "dans {days} jours",
2219
+ trashExpiresToday: "cette nuit",
2220
+ trashRestoredAs: "Restaur\xE9",
2221
+ trashEmpty: "La corbeille est vide.",
2222
+ trashFailed: "La corbeille n'a pas pu \xEAtre charg\xE9e.",
2223
+ trashPreview: "Aper\xE7u",
2224
+ trashRestore: "Restaurer",
2225
+ trashDelete: "Supprimer d\xE9finitivement",
2226
+ trashDeleteTitle: "Supprimer d\xE9finitivement",
2227
+ 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.",
2228
+ trashDeleted: "Supprim\xE9 d\xE9finitivement.",
2229
+ trashDeleteFailed: "La suppression a \xE9chou\xE9.",
2230
+ trashDraft: "brouillon",
2231
+ trashPublished: "publi\xE9",
2232
+ trashFields: "Champs",
2233
+ trashBlocks: "Blocs",
2234
+ trashItems: "{count} \xE9l\xE9ment(s)",
2235
+ trashIncoming: "{count} lien(s) depuis d'autres documents ou blocs ont \xE9t\xE9 conserv\xE9s.",
2236
+ trashClose: "Fermer",
2237
+ restoreTitle: "Restaurer \xAB {title} \xBB",
2238
+ restoreChecking: "V\xE9rification de ce que ferait la restauration\u2026",
2239
+ restoreIntro: "Le document revient en brouillon, avec le contenu du brouillon : v\xE9rifiez-le, puis publiez-le \xE0 nouveau.",
2240
+ restoreNew: "Un nouveau document est cr\xE9\xE9 (Strapi ne r\xE9utilise pas l'id d'origine).",
2241
+ restoreInto: "Les langues reviennent dans le document existant.",
2242
+ restoreLocales: "Langues restaur\xE9es : {locales}",
2243
+ restoreBlocked: "Il ne peut pas \xEAtre restaur\xE9 en l'\xE9tat (rien n'est \xE9crit) :",
2244
+ restoreWarnings: "Il est restaur\xE9 avec ces diff\xE9rences :",
2245
+ restoreConfirm: "Restaurer en brouillon",
2246
+ restoreCancel: "Annuler",
2247
+ restoreDone: "Restaur\xE9 en brouillon.",
2248
+ restoreAlready: "Cette entr\xE9e a d\xE9j\xE0 \xE9t\xE9 restaur\xE9e.",
2249
+ restoreFailed: "La restauration a \xE9chou\xE9 : rien n'a \xE9t\xE9 \xE9crit.",
2250
+ restoreOpen: "Ouvrir le document restaur\xE9",
2251
+ "report.typeGone": "Le type de contenu n'existe plus.",
2252
+ "report.localeExists": "Le document a de nouveau la langue {locale}.",
2253
+ "report.unique": "\xAB {value} \xBB est d\xE9j\xE0 utilis\xE9 dans {field} ({locale}) par un autre document.",
2254
+ "report.singleExists": "Ce type unique a de nouveau un document.",
2255
+ "report.nothing": "Rien \xE0 restaurer : aucune de ses langues n'est encore configur\xE9e.",
2256
+ "report.restored": "D\xE9j\xE0 restaur\xE9.",
2257
+ "report.published": "Une version publi\xE9e existait ({locales}) : elle reste dans l'entr\xE9e de la corbeille, c'est le brouillon qui revient.",
2258
+ "report.localeRemoved": "La langue {locale} n'est plus configur\xE9e : ignor\xE9e.",
2259
+ "report.required": "Champs obligatoires vides ({locale}) : {fields}. Remplissez-les avant de publier.",
2260
+ "report.fieldsRemoved": "Champs que le sch\xE9ma n'a plus, laiss\xE9s de c\xF4t\xE9 ({locale}) : {fields}.",
2261
+ "report.media": "{count} fichier(s) m\xE9dia n'existent plus, laiss\xE9s vides ({locale}).",
2262
+ "report.relations": "{count} document(s) li\xE9s n'existent plus, laiss\xE9s de c\xF4t\xE9 ({locale}).",
2263
+ "report.blocks": "{count} bloc(s) dont la zone n'autorise plus le composant, laiss\xE9s de c\xF4t\xE9 ({locale}).",
2264
+ "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).",
2265
+ groupCollapse: "Replier le groupe {label}",
2266
+ groupExpand: "D\xE9plier le groupe {label}",
2267
+ groupBlocks: "{count, plural, one {# bloc} other {# blocs}}"
1784
2268
  };
1785
2269
 
1786
2270
  // admin/translations/es.json
@@ -1788,7 +2272,6 @@ var es_default = {
1788
2272
  title: "Blockscene",
1789
2273
  settings: "Galer\xEDa",
1790
2274
  gallery: "Galer\xEDa de bloques",
1791
- add: "A\xF1adir bloque",
1792
2275
  search: "Buscar bloques",
1793
2276
  clear: "Borrar b\xFAsqueda",
1794
2277
  empty: "No se encontraron bloques.",
@@ -1798,8 +2281,9 @@ var es_default = {
1798
2281
  failed: "No se pudo cargar el cat\xE1logo. Cierre e int\xE9ntelo de nuevo.",
1799
2282
  insertFailed: "No se pudo crear este componente. Use el selector nativo e informe de su esquema.",
1800
2283
  example: "Las im\xE1genes son ejemplos; la apariencia depende de su frontend.",
1801
- openAll: "Abrir todos los bloques",
1802
- closeAll: "Cerrar todos los bloques",
2284
+ expandAll: "Expandir todo",
2285
+ collapseAll: "Contraer todo",
2286
+ moreActions: "M\xE1s acciones",
1803
2287
  settingsTitle: "Blockscene",
1804
2288
  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.",
1805
2289
  palette: "Paleta de wireframes",
@@ -1827,8 +2311,9 @@ var es_default = {
1827
2311
  editor: "Preferencias del editor",
1828
2312
  enabled: "Blockscene activado",
1829
2313
  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.",
1830
- showOpenAll: "Mostrar \xABAbrir todos los bloques\xBB",
1831
- showCloseAll: "Mostrar \xABCerrar todos los bloques\xBB",
2314
+ showOpenAll: "Mostrar \xABExpandir todo\xBB",
2315
+ showCloseAll: "Mostrar \xABContraer todo\xBB",
2316
+ 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.",
1832
2317
  showRowThumbnails: "Mostrar miniaturas de los bloques en las filas",
1833
2318
  initialState: "Estado inicial de los acordeones",
1834
2319
  "states.closed": "Todos cerrados",
@@ -1837,6 +2322,7 @@ var es_default = {
1837
2322
  rememberHelp: "Solo los botones expl\xEDcitos de abrir/cerrar todos actualizan la memoria, por usuario y navegador. Abrir un solo bloque no la cambia.",
1838
2323
  previewUrl: "URL base de la ruta de vista previa",
1839
2324
  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).",
2325
+ 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.",
1840
2326
  previewMode: "Modo inicial de la vista previa",
1841
2327
  "modes.form": "Campos",
1842
2328
  "modes.split": "Campos + p\xE1gina",
@@ -1855,8 +2341,6 @@ var es_default = {
1855
2341
  resize: "Redimensionar el panel de vista previa",
1856
2342
  resizeHint: "Arrastra para redimensionar; doble clic vuelve a la mitad",
1857
2343
  scrollToHovered: "Desplazarse al bloque resaltado",
1858
- 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.",
1859
- previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
1860
2344
  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.",
1861
2345
  previewLoading: "Cargando vista previa\u2026",
1862
2346
  retry: "Reintentar",
@@ -2001,8 +2485,13 @@ var es_default = {
2001
2485
  confirmDelete: "\xBFEliminar el bloque {name}?",
2002
2486
  confirmDeleteMarker: "Es un marcador de grupo: solo se elimina el marcador, no los bloques del grupo, y el grupo queda desequilibrado hasta corregirlo.",
2003
2487
  delete: "Eliminar",
2004
- selectMode: "Seleccionar bloques para copiar",
2005
- copySelected: "Copiar seleccionados ({count})",
2488
+ selectBlocks: "Seleccionar bloques",
2489
+ selectAll: "Seleccionar todos",
2490
+ selectNone: "Deseleccionar todos",
2491
+ selectedCount: "{count, plural, one {# seleccionado} other {# seleccionados}}",
2492
+ copy: "Copiar",
2493
+ copyNothing: "Selecciona al menos un bloque para copiar.",
2494
+ selectDone: "Listo",
2006
2495
  paste: "Pegar {count, plural, one {# bloque} other {# bloques}}",
2007
2496
  pasted: "{count, plural, one {# bloque pegado} other {# bloques pegados}}.",
2008
2497
  copied: "{count, plural, one {# bloque copiado} other {# bloques copiados}}. P\xE9galos en cualquier p\xE1gina de este sitio.",
@@ -2065,7 +2554,120 @@ var es_default = {
2065
2554
  historyMax: "Instant\xE1neas por documento (m\xE1ximo)",
2066
2555
  historyEventDays: "Conservar la actividad (d\xEDas)",
2067
2556
  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.",
2068
- 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."
2557
+ 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.",
2558
+ fieldHelp: "M\xE1s informaci\xF3n",
2559
+ paneTitle: "Barra de la vista previa de p\xE1gina",
2560
+ 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.",
2561
+ "toolbar.modes": "Modo de edici\xF3n",
2562
+ "toolbar.history": "Deshacer y rehacer",
2563
+ "toolbar.devices": "Men\xFA de ancho de p\xE1gina",
2564
+ "toolbar.status": "Estado del documento",
2565
+ "toolbar.actions": "Guardar y Publicar",
2566
+ paneDevices: "Anchos de p\xE1gina",
2567
+ 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.",
2568
+ paneAddWidth: "A\xF1adir ancho",
2569
+ paneWidthLabel: "Nombre",
2570
+ paneWidth: "Ancho (px)",
2571
+ paneRemoveWidth: "Quitar ancho",
2572
+ 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.",
2573
+ paneTypeOverride: "Barra de vista previa propia para {name}",
2574
+ add: "A\xF1adir bloque",
2575
+ openAll: "Abrir todos los bloques",
2576
+ closeAll: "Cerrar todos los bloques",
2577
+ 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.",
2578
+ previewNoUrl: "Sin URL de vista previa: def\xEDnala en Ajustes, Blockscene, o configure la Vista previa nativa de Strapi para este tipo de contenido.",
2579
+ selectMode: "Seleccionar bloques para copiar",
2580
+ copySelected: "Copiar seleccionados ({count})",
2581
+ trashDays: "Conservar documentos eliminados (d\xEDas)",
2582
+ 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.",
2583
+ "historyActions.purge": "Eliminado definitivamente",
2584
+ contentMenu: "Actividad y papelera",
2585
+ contentTitle: "Actividad del contenido y papelera",
2586
+ contentSubtitle: "Cambios hechos a trav\xE9s de Strapi (admin, API, plugins) en los tipos de contenido que cubre el historial de versiones.",
2587
+ 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.",
2588
+ contentLoading: "Cargando\u2026",
2589
+ contentNone: "\u2014",
2590
+ contentUntitled: "(sin t\xEDtulo)",
2591
+ contentGone: "ya no existe",
2592
+ contentOpen: "Abrir",
2593
+ contentPrevious: "Anterior",
2594
+ contentNext: "Siguiente",
2595
+ contentPage: "P\xE1gina {page} de {pages}, {total} en total",
2596
+ contentClear: "Borrar filtros",
2597
+ activityTab: "Actividad",
2598
+ activityPerson: "Persona",
2599
+ activityAnyone: "Cualquiera",
2600
+ activityType: "Tipo de contenido",
2601
+ activityAnyType: "Todos los tipos de contenido",
2602
+ activityAction: "Acci\xF3n",
2603
+ activityAnyAction: "Todas las acciones",
2604
+ activityFrom: "Desde",
2605
+ activityTo: "Hasta",
2606
+ activitySearch: "El t\xEDtulo contiene",
2607
+ activitySearchButton: "Buscar",
2608
+ activityWhen: "Cu\xE1ndo",
2609
+ activityDocument: "Documento",
2610
+ activityWho: "Qui\xE9n",
2611
+ activityWhat: "Qu\xE9",
2612
+ activityEmpty: "Ninguna actividad coincide con estos filtros.",
2613
+ activityFailed: "No se pudo cargar la actividad.",
2614
+ activityRestoredFrom: "Recuperado de la papelera",
2615
+ trashTab: "Papelera",
2616
+ trashShowRestored: "Mostrar entradas restauradas",
2617
+ trashLocales: "Idiomas",
2618
+ trashDeletedBy: "Eliminado por",
2619
+ trashDeletedAt: "Eliminado",
2620
+ trashExpires: "Borrado definitivo",
2621
+ trashExpiresIn: "en {days} d\xEDas",
2622
+ trashExpiresToday: "esta noche",
2623
+ trashRestoredAs: "Restaurado",
2624
+ trashEmpty: "La papelera est\xE1 vac\xEDa.",
2625
+ trashFailed: "No se pudo cargar la papelera.",
2626
+ trashPreview: "Vista previa",
2627
+ trashRestore: "Restaurar",
2628
+ trashDelete: "Eliminar definitivamente",
2629
+ trashDeleteTitle: "Eliminar definitivamente",
2630
+ trashDeleteConfirm: "\xBFEliminar \xAB{title}\xBB de la papelera definitivamente? Despu\xE9s no se podr\xE1 restaurar. Los archivos multimedia no se borran.",
2631
+ trashDeleted: "Eliminado definitivamente.",
2632
+ trashDeleteFailed: "No se pudo eliminar.",
2633
+ trashDraft: "borrador",
2634
+ trashPublished: "publicado",
2635
+ trashFields: "Campos",
2636
+ trashBlocks: "Bloques",
2637
+ trashItems: "{count} elemento(s)",
2638
+ trashIncoming: "Se guardaron {count} v\xEDnculo(s) desde otros documentos o bloques.",
2639
+ trashClose: "Cerrar",
2640
+ restoreTitle: "Restaurar \xAB{title}\xBB",
2641
+ restoreChecking: "Comprobando lo que har\xEDa la restauraci\xF3n\u2026",
2642
+ restoreIntro: "El documento vuelve como borrador, con el contenido del borrador: rev\xEDsalo y vuelve a publicarlo.",
2643
+ restoreNew: "Se crea un documento nuevo (Strapi no reutiliza el id original).",
2644
+ restoreInto: "Los idiomas vuelven al documento que ya existe.",
2645
+ restoreLocales: "Idiomas restaurados: {locales}",
2646
+ restoreBlocked: "No se puede restaurar tal como est\xE1 (no se escribe nada):",
2647
+ restoreWarnings: "Se restaura con estas diferencias:",
2648
+ restoreConfirm: "Restaurar como borrador",
2649
+ restoreCancel: "Cancelar",
2650
+ restoreDone: "Restaurado como borrador.",
2651
+ restoreAlready: "Esta entrada ya se restaur\xF3.",
2652
+ restoreFailed: "La restauraci\xF3n fall\xF3: no se escribi\xF3 nada.",
2653
+ restoreOpen: "Abrir el documento restaurado",
2654
+ "report.typeGone": "El tipo de contenido ya no existe.",
2655
+ "report.localeExists": "El documento vuelve a tener el idioma {locale}.",
2656
+ "report.unique": "\xAB{value}\xBB ya se usa en {field} ({locale}) en otro documento.",
2657
+ "report.singleExists": "Este tipo \xFAnico vuelve a tener un documento.",
2658
+ "report.nothing": "No hay nada que restaurar: ninguno de sus idiomas sigue configurado.",
2659
+ "report.restored": "Ya restaurado.",
2660
+ "report.published": "Exist\xEDa una versi\xF3n publicada ({locales}): queda guardada en la entrada de la papelera; lo que vuelve es el borrador.",
2661
+ "report.localeRemoved": "El idioma {locale} ya no est\xE1 configurado: se omite.",
2662
+ "report.required": "Campos obligatorios vac\xEDos ({locale}): {fields}. Compl\xE9talos antes de publicar.",
2663
+ "report.fieldsRemoved": "Campos que el esquema ya no tiene, omitidos ({locale}): {fields}.",
2664
+ "report.media": "{count} archivo(s) multimedia ya no existen, quedan vac\xEDos ({locale}).",
2665
+ "report.relations": "{count} documento(s) relacionados ya no existen, omitidos ({locale}).",
2666
+ "report.blocks": "{count} bloque(s) cuyo componente la zona ya no permite, omitidos ({locale}).",
2667
+ "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).",
2668
+ groupCollapse: "Contraer el grupo {label}",
2669
+ groupExpand: "Expandir el grupo {label}",
2670
+ groupBlocks: "{count, plural, one {# bloque} other {# bloques}}"
2069
2671
  };
2070
2672
 
2071
2673
  // admin/translations/de.json
@@ -2073,7 +2675,6 @@ var de_default = {
2073
2675
  title: "Blockscene",
2074
2676
  settings: "Galerie",
2075
2677
  gallery: "Blockgalerie",
2076
- add: "Block hinzuf\xFCgen",
2077
2678
  search: "Bl\xF6cke suchen",
2078
2679
  clear: "Suche l\xF6schen",
2079
2680
  empty: "Keine Bl\xF6cke gefunden.",
@@ -2083,8 +2684,9 @@ var de_default = {
2083
2684
  failed: "Der Katalog konnte nicht geladen werden. Schlie\xDFen und erneut versuchen.",
2084
2685
  insertFailed: "Diese Komponente konnte nicht erstellt werden. Verwenden Sie die native Auswahl und melden Sie ihr Schema.",
2085
2686
  example: "Bilder sind Beispiele; das Aussehen h\xE4ngt von Ihrem Frontend ab.",
2086
- openAll: "Alle Bl\xF6cke \xF6ffnen",
2087
- closeAll: "Alle Bl\xF6cke schlie\xDFen",
2687
+ expandAll: "Alle aufklappen",
2688
+ collapseAll: "Alle zuklappen",
2689
+ moreActions: "Weitere Aktionen",
2088
2690
  settingsTitle: "Blockscene",
2089
2691
  settingsIntro: "Galerie-Vorschaubilder, Wireframe-Palette und Editor-Einstellungen. \xC4nderungen gelten beim n\xE4chsten \xD6ffnen der Galerie; kein Rebuild n\xF6tig.",
2090
2692
  palette: "Wireframe-Palette",
@@ -2112,8 +2714,9 @@ var de_default = {
2112
2714
  editor: "Editor-Einstellungen",
2113
2715
  enabled: "Blockscene aktiv",
2114
2716
  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.",
2115
- showOpenAll: "\u201EAlle Bl\xF6cke \xF6ffnen\u201C anzeigen",
2116
- showCloseAll: "\u201EAlle Bl\xF6cke schlie\xDFen\u201C anzeigen",
2717
+ showOpenAll: "\u201EAlle aufklappen\u201C anzeigen",
2718
+ showCloseAll: "\u201EAlle zuklappen\u201C anzeigen",
2719
+ 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.",
2117
2720
  showRowThumbnails: "Blockvorschaubilder in den Zeilen anzeigen",
2118
2721
  initialState: "Anfangszustand der Akkordeons",
2119
2722
  "states.closed": "Alle geschlossen",
@@ -2122,6 +2725,7 @@ var de_default = {
2122
2725
  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.",
2123
2726
  previewUrl: "Basis-URL der Vorschauroute",
2124
2727
  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).",
2728
+ 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.",
2125
2729
  previewMode: "Anf\xE4nglicher Vorschaumodus",
2126
2730
  "modes.form": "Felder",
2127
2731
  "modes.split": "Felder + Seite",
@@ -2140,8 +2744,6 @@ var de_default = {
2140
2744
  resize: "Vorschaubereich anpassen",
2141
2745
  resizeHint: "Ziehen zum \xC4ndern der Gr\xF6\xDFe; Doppelklick setzt auf die H\xE4lfte zur\xFCck",
2142
2746
  scrollToHovered: "Zum hervorgehobenen Block scrollen",
2143
- 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.",
2144
- previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
2145
2747
  previewFailed: "Die Vorschau hat innerhalb von 15 s nicht geantwortet. L\xE4dt das Frontend noch, erscheint sie von selbst; das Formular bleibt benutzbar.",
2146
2748
  previewLoading: "Vorschau wird geladen\u2026",
2147
2749
  retry: "Erneut versuchen",
@@ -2286,8 +2888,13 @@ var de_default = {
2286
2888
  confirmDelete: "Block {name} l\xF6schen?",
2287
2889
  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.",
2288
2890
  delete: "L\xF6schen",
2289
- selectMode: "Bl\xF6cke zum Kopieren ausw\xE4hlen",
2290
- copySelected: "Auswahl kopieren ({count})",
2891
+ selectBlocks: "Bl\xF6cke ausw\xE4hlen",
2892
+ selectAll: "Alle ausw\xE4hlen",
2893
+ selectNone: "Auswahl aufheben",
2894
+ selectedCount: "{count} ausgew\xE4hlt",
2895
+ copy: "Kopieren",
2896
+ copyNothing: "W\xE4hlen Sie mindestens einen Block zum Kopieren aus.",
2897
+ selectDone: "Fertig",
2291
2898
  paste: "{count, plural, one {# Block} other {# Bl\xF6cke}} einf\xFCgen",
2292
2899
  pasted: "{count, plural, one {# Block eingef\xFCgt} other {# Bl\xF6cke eingef\xFCgt}}.",
2293
2900
  copied: "{count, plural, one {# Block kopiert} other {# Bl\xF6cke kopiert}}. Auf jeder Seite dieser Website einf\xFCgbar.",
@@ -2350,7 +2957,120 @@ var de_default = {
2350
2957
  historyMax: "Snapshots pro Dokument (Maximum)",
2351
2958
  historyEventDays: "Aktivit\xE4t aufbewahren (Tage)",
2352
2959
  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.",
2353
- historyInvalid: "Ganze Zahlen: 1 bis 3650 Tage (die Aktivit\xE4t mindestens so lange wie die Snapshots) und 1 bis 1000 Snapshots."
2960
+ historyInvalid: "Ganze Zahlen: 1 bis 3650 Tage (die Aktivit\xE4t mindestens so lange wie die Snapshots) und 1 bis 1000 Snapshots.",
2961
+ fieldHelp: "Weitere Informationen",
2962
+ paneTitle: "Werkzeugleiste der Seitenvorschau",
2963
+ paneHelp: "Markierte Bedienelemente erscheinen in dieser Reihenfolge in der Werkzeugleiste der Seitenvorschau. Status und Speichern/Ver\xF6ffentlichen bleiben rechts zusammen; nicht markierte sind ausgeblendet.",
2964
+ "toolbar.modes": "Bearbeitungsmodus",
2965
+ "toolbar.history": "R\xFCckg\xE4ngig und Wiederholen",
2966
+ "toolbar.devices": "Men\xFC der Seitenbreite",
2967
+ "toolbar.status": "Dokumentstatus",
2968
+ "toolbar.actions": "Speichern und Ver\xF6ffentlichen",
2969
+ paneDevices: "Seitenbreiten",
2970
+ paneDevicesHelp: "Eintr\xE4ge des Breitenmen\xFCs in Reihenfolge; der erste gilt, bis eine Redaktion einen anderen w\xE4hlt. Eigene Breiten: 240 bis 3840 px.",
2971
+ paneAddWidth: "Breite hinzuf\xFCgen",
2972
+ paneWidthLabel: "Bezeichnung",
2973
+ paneWidth: "Breite (px)",
2974
+ paneRemoveWidth: "Breite entfernen",
2975
+ 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.",
2976
+ paneTypeOverride: "Eigene Vorschau-Werkzeugleiste f\xFCr {name}",
2977
+ add: "Block hinzuf\xFCgen",
2978
+ openAll: "Alle Bl\xF6cke \xF6ffnen",
2979
+ closeAll: "Alle Bl\xF6cke schlie\xDFen",
2980
+ 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.",
2981
+ previewNoUrl: "Keine Vorschau-URL: in Einstellungen, Blockscene festlegen oder die native Strapi-Vorschau f\xFCr diesen Inhaltstyp konfigurieren.",
2982
+ selectMode: "Bl\xF6cke zum Kopieren ausw\xE4hlen",
2983
+ copySelected: "Auswahl kopieren ({count})",
2984
+ trashDays: "Gel\xF6schte Dokumente aufbewahren (Tage)",
2985
+ trashDaysHelp: "Gel\xF6schte Dokumente bleiben so viele Tage im Papierkorb (beim L\xF6schen jeweils festgelegt), danach entfernt sie der n\xE4chtliche Job.",
2986
+ "historyActions.purge": "Endg\xFCltig gel\xF6scht",
2987
+ contentMenu: "Aktivit\xE4t und Papierkorb",
2988
+ contentTitle: "Inhaltsaktivit\xE4t und Papierkorb",
2989
+ contentSubtitle: "\xC4nderungen \xFCber Strapi (Admin, API, Plugins) an den Inhaltstypen, die der Versionsverlauf abdeckt.",
2990
+ contentOff: "Der Versionsverlauf ist aus: Neues wird weder aufgezeichnet noch in den Papierkorb gelegt. Aktivieren unter Einstellungen, Blockscene.",
2991
+ contentLoading: "Wird geladen\u2026",
2992
+ contentNone: "\u2014",
2993
+ contentUntitled: "(ohne Titel)",
2994
+ contentGone: "existiert nicht mehr",
2995
+ contentOpen: "\xD6ffnen",
2996
+ contentPrevious: "Zur\xFCck",
2997
+ contentNext: "Weiter",
2998
+ contentPage: "Seite {page} von {pages}, insgesamt {total}",
2999
+ contentClear: "Filter zur\xFCcksetzen",
3000
+ activityTab: "Aktivit\xE4t",
3001
+ activityPerson: "Person",
3002
+ activityAnyone: "Alle",
3003
+ activityType: "Inhaltstyp",
3004
+ activityAnyType: "Alle Inhaltstypen",
3005
+ activityAction: "Aktion",
3006
+ activityAnyAction: "Alle Aktionen",
3007
+ activityFrom: "Von",
3008
+ activityTo: "Bis",
3009
+ activitySearch: "Titel enth\xE4lt",
3010
+ activitySearchButton: "Suchen",
3011
+ activityWhen: "Wann",
3012
+ activityDocument: "Dokument",
3013
+ activityWho: "Wer",
3014
+ activityWhat: "Was",
3015
+ activityEmpty: "Keine Aktivit\xE4t passt zu diesen Filtern.",
3016
+ activityFailed: "Die Aktivit\xE4t konnte nicht geladen werden.",
3017
+ activityRestoredFrom: "Aus dem Papierkorb zur\xFCck",
3018
+ trashTab: "Papierkorb",
3019
+ trashShowRestored: "Wiederhergestellte Eintr\xE4ge anzeigen",
3020
+ trashLocales: "Sprachen",
3021
+ trashDeletedBy: "Gel\xF6scht von",
3022
+ trashDeletedAt: "Gel\xF6scht",
3023
+ trashExpires: "Endg\xFCltig gel\xF6scht",
3024
+ trashExpiresIn: "in {days} Tagen",
3025
+ trashExpiresToday: "heute Nacht",
3026
+ trashRestoredAs: "Wiederhergestellt",
3027
+ trashEmpty: "Der Papierkorb ist leer.",
3028
+ trashFailed: "Der Papierkorb konnte nicht geladen werden.",
3029
+ trashPreview: "Vorschau",
3030
+ trashRestore: "Wiederherstellen",
3031
+ trashDelete: "Endg\xFCltig l\xF6schen",
3032
+ trashDeleteTitle: "Endg\xFCltig l\xF6schen",
3033
+ trashDeleteConfirm: "\u201E{title}\u201C endg\xFCltig aus dem Papierkorb l\xF6schen? Danach l\xE4sst es sich nicht wiederherstellen. Mediendateien werden nicht gel\xF6scht.",
3034
+ trashDeleted: "Endg\xFCltig gel\xF6scht.",
3035
+ trashDeleteFailed: "Es konnte nicht gel\xF6scht werden.",
3036
+ trashDraft: "Entwurf",
3037
+ trashPublished: "ver\xF6ffentlicht",
3038
+ trashFields: "Felder",
3039
+ trashBlocks: "Bl\xF6cke",
3040
+ trashItems: "{count} Element(e)",
3041
+ trashIncoming: "{count} Verkn\xFCpfung(en) aus anderen Dokumenten oder Bl\xF6cken wurden gesichert.",
3042
+ trashClose: "Schlie\xDFen",
3043
+ restoreTitle: "\u201E{title}\u201C wiederherstellen",
3044
+ restoreChecking: "Es wird gepr\xFCft, was die Wiederherstellung tun w\xFCrde\u2026",
3045
+ restoreIntro: "Das Dokument kommt als Entwurf zur\xFCck, mit dem Inhalt des Entwurfs: pr\xFCfen und dann erneut ver\xF6ffentlichen.",
3046
+ restoreNew: "Ein neues Dokument wird angelegt (Strapi verwendet die urspr\xFCngliche ID nicht wieder).",
3047
+ restoreInto: "Die Sprachen kommen in das bestehende Dokument zur\xFCck.",
3048
+ restoreLocales: "Wiederhergestellte Sprachen: {locales}",
3049
+ restoreBlocked: "So kann es nicht wiederhergestellt werden (nichts wird geschrieben):",
3050
+ restoreWarnings: "Es wird mit diesen Abweichungen wiederhergestellt:",
3051
+ restoreConfirm: "Als Entwurf wiederherstellen",
3052
+ restoreCancel: "Abbrechen",
3053
+ restoreDone: "Als Entwurf wiederhergestellt.",
3054
+ restoreAlready: "Dieser Eintrag wurde bereits wiederhergestellt.",
3055
+ restoreFailed: "Die Wiederherstellung ist fehlgeschlagen: nichts wurde geschrieben.",
3056
+ restoreOpen: "Wiederhergestelltes Dokument \xF6ffnen",
3057
+ "report.typeGone": "Der Inhaltstyp existiert nicht mehr.",
3058
+ "report.localeExists": "Das Dokument hat die Sprache {locale} wieder.",
3059
+ "report.unique": "\u201E{value}\u201C wird in {field} ({locale}) bereits von einem anderen Dokument verwendet.",
3060
+ "report.singleExists": "Dieser Single Type hat wieder ein Dokument.",
3061
+ "report.nothing": "Nichts wiederherzustellen: keine seiner Sprachen ist noch konfiguriert.",
3062
+ "report.restored": "Bereits wiederhergestellt.",
3063
+ "report.published": "Es gab eine ver\xF6ffentlichte Version ({locales}): sie bleibt im Papierkorbeintrag, zur\xFCck kommt der Entwurf.",
3064
+ "report.localeRemoved": "Die Sprache {locale} ist nicht mehr konfiguriert: \xFCbersprungen.",
3065
+ "report.required": "Leere Pflichtfelder ({locale}): {fields}. Vor dem Ver\xF6ffentlichen ausf\xFCllen.",
3066
+ "report.fieldsRemoved": "Felder, die das Schema nicht mehr hat, ausgelassen ({locale}): {fields}.",
3067
+ "report.media": "{count} Mediendatei(en) existieren nicht mehr, leer gelassen ({locale}).",
3068
+ "report.relations": "{count} verkn\xFCpfte(s) Dokument(e) existieren nicht mehr, ausgelassen ({locale}).",
3069
+ "report.blocks": "{count} Block/Bl\xF6cke, deren Komponente die Zone nicht mehr erlaubt, ausgelassen ({locale}).",
3070
+ "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).",
3071
+ groupCollapse: "Gruppe {label} einklappen",
3072
+ groupExpand: "Gruppe {label} ausklappen",
3073
+ groupBlocks: "{count, plural, one {# Block} other {# Bl\xF6cke}}"
2354
3074
  };
2355
3075
 
2356
3076
  // admin/translations/it.json
@@ -2358,7 +3078,6 @@ var it_default = {
2358
3078
  title: "Blockscene",
2359
3079
  settings: "Galleria",
2360
3080
  gallery: "Galleria dei blocchi",
2361
- add: "Aggiungi blocco",
2362
3081
  search: "Cerca blocchi",
2363
3082
  clear: "Cancella ricerca",
2364
3083
  empty: "Nessun blocco trovato.",
@@ -2368,8 +3087,9 @@ var it_default = {
2368
3087
  failed: "Impossibile caricare il catalogo. Chiudi e riprova.",
2369
3088
  insertFailed: "Impossibile creare questo componente. Usa il selettore nativo e segnala il suo schema.",
2370
3089
  example: "Le immagini sono esempi; l'aspetto dipende dal tuo frontend.",
2371
- openAll: "Apri tutti i blocchi",
2372
- closeAll: "Chiudi tutti i blocchi",
3090
+ expandAll: "Espandi tutto",
3091
+ collapseAll: "Comprimi tutto",
3092
+ moreActions: "Altre azioni",
2373
3093
  settingsTitle: "Blockscene",
2374
3094
  settingsIntro: "Miniature della galleria, palette dei wireframe e preferenze dell'editor. Le modifiche valgono alla prossima apertura della galleria; non serve alcun rebuild.",
2375
3095
  palette: "Palette dei wireframe",
@@ -2397,8 +3117,9 @@ var it_default = {
2397
3117
  editor: "Preferenze dell'editor",
2398
3118
  enabled: "Blockscene attivo",
2399
3119
  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.",
2400
- showOpenAll: 'Mostra "Apri tutti i blocchi"',
2401
- showCloseAll: 'Mostra "Chiudi tutti i blocchi"',
3120
+ showOpenAll: 'Mostra "Espandi tutto"',
3121
+ showCloseAll: 'Mostra "Comprimi tutto"',
3122
+ 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.",
2402
3123
  showRowThumbnails: "Mostra le miniature dei blocchi nelle righe",
2403
3124
  initialState: "Stato iniziale delle fisarmoniche",
2404
3125
  "states.closed": "Tutte chiuse",
@@ -2407,6 +3128,7 @@ var it_default = {
2407
3128
  rememberHelp: "Solo i pulsanti espliciti apri tutti / chiudi tutti aggiornano la memoria, per utente e browser. Aprire un singolo blocco non la cambia.",
2408
3129
  previewUrl: "URL di base della route di anteprima",
2409
3130
  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).",
3131
+ 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.",
2410
3132
  previewMode: "Modalit\xE0 iniziale dell'anteprima",
2411
3133
  "modes.form": "Campi",
2412
3134
  "modes.split": "Campi + pagina",
@@ -2425,8 +3147,6 @@ var it_default = {
2425
3147
  resize: "Ridimensiona il pannello di anteprima",
2426
3148
  resizeHint: "Trascina per ridimensionare; doppio clic per tornare a met\xE0",
2427
3149
  scrollToHovered: "Scorri fino al blocco evidenziato",
2428
- 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.",
2429
- previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
2430
3150
  previewFailed: "L'anteprima non ha risposto entro 15 s. Se il frontend sta ancora caricando, comparir\xE0 da sola; il modulo resta utilizzabile.",
2431
3151
  previewLoading: "Caricamento dell'anteprima\u2026",
2432
3152
  retry: "Riprova",
@@ -2571,8 +3291,13 @@ var it_default = {
2571
3291
  confirmDelete: "Eliminare il blocco {name}?",
2572
3292
  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.",
2573
3293
  delete: "Elimina",
2574
- selectMode: "Seleziona i blocchi da copiare",
2575
- copySelected: "Copia selezionati ({count})",
3294
+ selectBlocks: "Seleziona blocchi",
3295
+ selectAll: "Seleziona tutti",
3296
+ selectNone: "Deseleziona tutti",
3297
+ selectedCount: "{count, plural, one {# selezionato} other {# selezionati}}",
3298
+ copy: "Copia",
3299
+ copyNothing: "Seleziona almeno un blocco da copiare.",
3300
+ selectDone: "Fine",
2576
3301
  paste: "Incolla {count, plural, one {# blocco} other {# blocchi}}",
2577
3302
  pasted: "{count, plural, one {# blocco incollato} other {# blocchi incollati}}.",
2578
3303
  copied: "{count, plural, one {# blocco copiato} other {# blocchi copiati}}. Incollali in qualsiasi pagina di questo sito.",
@@ -2635,7 +3360,120 @@ var it_default = {
2635
3360
  historyMax: "Istantanee per documento (massimo)",
2636
3361
  historyEventDays: "Conserva l'attivit\xE0 (giorni)",
2637
3362
  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.",
2638
- historyInvalid: "Numeri interi: da 1 a 3650 giorni (l'attivit\xE0 conservata almeno quanto le istantanee) e da 1 a 1000 istantanee."
3363
+ historyInvalid: "Numeri interi: da 1 a 3650 giorni (l'attivit\xE0 conservata almeno quanto le istantanee) e da 1 a 1000 istantanee.",
3364
+ fieldHelp: "Maggiori informazioni",
3365
+ paneTitle: "Barra dell'anteprima pagina",
3366
+ 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.",
3367
+ "toolbar.modes": "Modalit\xE0 di modifica",
3368
+ "toolbar.history": "Annulla e ripeti",
3369
+ "toolbar.devices": "Menu della larghezza pagina",
3370
+ "toolbar.status": "Stato del documento",
3371
+ "toolbar.actions": "Salva e Pubblica",
3372
+ paneDevices: "Larghezze della pagina",
3373
+ 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.",
3374
+ paneAddWidth: "Aggiungi larghezza",
3375
+ paneWidthLabel: "Etichetta",
3376
+ paneWidth: "Larghezza (px)",
3377
+ paneRemoveWidth: "Rimuovi larghezza",
3378
+ 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.",
3379
+ paneTypeOverride: "Barra dell'anteprima propria per {name}",
3380
+ add: "Aggiungi blocco",
3381
+ openAll: "Apri tutti i blocchi",
3382
+ closeAll: "Chiudi tutti i blocchi",
3383
+ 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.",
3384
+ previewNoUrl: "Nessun URL di anteprima: impostalo in Impostazioni, Blockscene, oppure configura l'Anteprima nativa di Strapi per questo tipo di contenuto.",
3385
+ selectMode: "Seleziona i blocchi da copiare",
3386
+ copySelected: "Copia selezionati ({count})",
3387
+ trashDays: "Conserva i documenti eliminati (giorni)",
3388
+ trashDaysHelp: "I documenti eliminati restano nel cestino per questo numero di giorni (fissato quando ognuno viene eliminato), poi l'attivit\xE0 notturna li cancella.",
3389
+ "historyActions.purge": "Eliminato definitivamente",
3390
+ contentMenu: "Attivit\xE0 e cestino",
3391
+ contentTitle: "Attivit\xE0 dei contenuti e cestino",
3392
+ contentSubtitle: "Modifiche fatte tramite Strapi (admin, API, plugin) ai tipi di contenuto coperti dalla cronologia delle versioni.",
3393
+ contentOff: "La cronologia delle versioni \xE8 disattivata: niente di nuovo viene registrato o messo nel cestino. Attivala in Impostazioni, Blockscene.",
3394
+ contentLoading: "Caricamento\u2026",
3395
+ contentNone: "\u2014",
3396
+ contentUntitled: "(senza titolo)",
3397
+ contentGone: "non esiste pi\xF9",
3398
+ contentOpen: "Apri",
3399
+ contentPrevious: "Precedente",
3400
+ contentNext: "Successiva",
3401
+ contentPage: "Pagina {page} di {pages}, {total} in totale",
3402
+ contentClear: "Azzera i filtri",
3403
+ activityTab: "Attivit\xE0",
3404
+ activityPerson: "Persona",
3405
+ activityAnyone: "Chiunque",
3406
+ activityType: "Tipo di contenuto",
3407
+ activityAnyType: "Tutti i tipi di contenuto",
3408
+ activityAction: "Azione",
3409
+ activityAnyAction: "Tutte le azioni",
3410
+ activityFrom: "Dal",
3411
+ activityTo: "Al",
3412
+ activitySearch: "Il titolo contiene",
3413
+ activitySearchButton: "Cerca",
3414
+ activityWhen: "Quando",
3415
+ activityDocument: "Documento",
3416
+ activityWho: "Chi",
3417
+ activityWhat: "Cosa",
3418
+ activityEmpty: "Nessuna attivit\xE0 corrisponde a questi filtri.",
3419
+ activityFailed: "Non \xE8 stato possibile caricare l'attivit\xE0.",
3420
+ activityRestoredFrom: "Recuperato dal cestino",
3421
+ trashTab: "Cestino",
3422
+ trashShowRestored: "Mostra le voci ripristinate",
3423
+ trashLocales: "Lingue",
3424
+ trashDeletedBy: "Eliminato da",
3425
+ trashDeletedAt: "Eliminato",
3426
+ trashExpires: "Eliminazione definitiva",
3427
+ trashExpiresIn: "tra {days} giorni",
3428
+ trashExpiresToday: "stanotte",
3429
+ trashRestoredAs: "Ripristinato",
3430
+ trashEmpty: "Il cestino \xE8 vuoto.",
3431
+ trashFailed: "Non \xE8 stato possibile caricare il cestino.",
3432
+ trashPreview: "Anteprima",
3433
+ trashRestore: "Ripristina",
3434
+ trashDelete: "Elimina definitivamente",
3435
+ trashDeleteTitle: "Elimina definitivamente",
3436
+ trashDeleteConfirm: "Eliminare definitivamente \u201C{title}\u201D dal cestino? Dopo non potr\xE0 pi\xF9 essere ripristinato. I file multimediali non vengono eliminati.",
3437
+ trashDeleted: "Eliminato definitivamente.",
3438
+ trashDeleteFailed: "Non \xE8 stato possibile eliminarlo.",
3439
+ trashDraft: "bozza",
3440
+ trashPublished: "pubblicato",
3441
+ trashFields: "Campi",
3442
+ trashBlocks: "Blocchi",
3443
+ trashItems: "{count} elemento/i",
3444
+ trashIncoming: "Sono stati conservati {count} collegamento/i da altri documenti o blocchi.",
3445
+ trashClose: "Chiudi",
3446
+ restoreTitle: "Ripristina \u201C{title}\u201D",
3447
+ restoreChecking: "Verifica di cosa farebbe il ripristino\u2026",
3448
+ restoreIntro: "Il documento torna come bozza, con il contenuto della bozza: controllalo e poi pubblicalo di nuovo.",
3449
+ restoreNew: "Viene creato un nuovo documento (Strapi non riutilizza l'id originale).",
3450
+ restoreInto: "Le lingue tornano nel documento esistente.",
3451
+ restoreLocales: "Lingue ripristinate: {locales}",
3452
+ restoreBlocked: "Non pu\xF2 essere ripristinato cos\xEC com'\xE8 (non viene scritto nulla):",
3453
+ restoreWarnings: "Viene ripristinato con queste differenze:",
3454
+ restoreConfirm: "Ripristina come bozza",
3455
+ restoreCancel: "Annulla",
3456
+ restoreDone: "Ripristinato come bozza.",
3457
+ restoreAlready: "Questa voce \xE8 gi\xE0 stata ripristinata.",
3458
+ restoreFailed: "Il ripristino non \xE8 riuscito: non \xE8 stato scritto nulla.",
3459
+ restoreOpen: "Apri il documento ripristinato",
3460
+ "report.typeGone": "Il tipo di contenuto non esiste pi\xF9.",
3461
+ "report.localeExists": "Il documento ha di nuovo la lingua {locale}.",
3462
+ "report.unique": "\u201C{value}\u201D \xE8 gi\xE0 usato in {field} ({locale}) da un altro documento.",
3463
+ "report.singleExists": "Questo single type ha di nuovo un documento.",
3464
+ "report.nothing": "Niente da ripristinare: nessuna delle sue lingue \xE8 ancora configurata.",
3465
+ "report.restored": "Gi\xE0 ripristinato.",
3466
+ "report.published": "Esisteva una versione pubblicata ({locales}): resta nella voce del cestino, torna la bozza.",
3467
+ "report.localeRemoved": "La lingua {locale} non \xE8 pi\xF9 configurata: saltata.",
3468
+ "report.required": "Campi obbligatori vuoti ({locale}): {fields}. Compilali prima di pubblicare.",
3469
+ "report.fieldsRemoved": "Campi che lo schema non ha pi\xF9, esclusi ({locale}): {fields}.",
3470
+ "report.media": "{count} file multimediale/i non esistono pi\xF9, lasciati vuoti ({locale}).",
3471
+ "report.relations": "{count} documento/i collegati non esistono pi\xF9, esclusi ({locale}).",
3472
+ "report.blocks": "{count} blocco/i il cui componente la zona non consente pi\xF9, esclusi ({locale}).",
3473
+ "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).",
3474
+ groupCollapse: "Comprimi il gruppo {label}",
3475
+ groupExpand: "Espandi il gruppo {label}",
3476
+ groupBlocks: "{count, plural, one {# blocco} other {# blocchi}}"
2639
3477
  };
2640
3478
 
2641
3479
  // admin/translations/nl.json
@@ -2643,7 +3481,6 @@ var nl_default = {
2643
3481
  title: "Blockscene",
2644
3482
  settings: "Galerij",
2645
3483
  gallery: "Blokkengalerij",
2646
- add: "Blok toevoegen",
2647
3484
  search: "Blokken zoeken",
2648
3485
  clear: "Zoekopdracht wissen",
2649
3486
  empty: "Geen blokken gevonden.",
@@ -2653,8 +3490,9 @@ var nl_default = {
2653
3490
  failed: "De catalogus kon niet worden geladen. Sluit en probeer opnieuw.",
2654
3491
  insertFailed: "Dit component kon niet worden aangemaakt. Gebruik de native kiezer en meld het schema.",
2655
3492
  example: "Afbeeldingen zijn voorbeelden; het uiterlijk hangt af van uw frontend.",
2656
- openAll: "Alle blokken openen",
2657
- closeAll: "Alle blokken sluiten",
3493
+ expandAll: "Alles uitklappen",
3494
+ collapseAll: "Alles inklappen",
3495
+ moreActions: "Meer acties",
2658
3496
  settingsTitle: "Blockscene",
2659
3497
  settingsIntro: "Galerijminiaturen, wireframe-palet en editorvoorkeuren. Wijzigingen gelden bij de volgende opening van de galerij; geen rebuild nodig.",
2660
3498
  palette: "Wireframe-palet",
@@ -2682,8 +3520,9 @@ var nl_default = {
2682
3520
  editor: "Editorvoorkeuren",
2683
3521
  enabled: "Blockscene aan",
2684
3522
  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.",
2685
- showOpenAll: '"Alle blokken openen" tonen',
2686
- showCloseAll: '"Alle blokken sluiten" tonen',
3523
+ showOpenAll: '"Alles uitklappen" tonen',
3524
+ showCloseAll: '"Alles inklappen" tonen',
3525
+ 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.",
2687
3526
  showRowThumbnails: "Blokminiaturen in de rijen tonen",
2688
3527
  initialState: "Beginstand van de accordeons",
2689
3528
  "states.closed": "Alle gesloten",
@@ -2692,6 +3531,7 @@ var nl_default = {
2692
3531
  rememberHelp: "Alleen de expliciete knoppen alles openen / alles sluiten werken het geheugen bij, per gebruiker en browser. E\xE9n blok openen verandert niets.",
2693
3532
  previewUrl: "Basis-URL van de voorbeeldroute",
2694
3533
  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).",
3534
+ 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.",
2695
3535
  previewMode: "Beginmodus van het voorbeeld",
2696
3536
  "modes.form": "Velden",
2697
3537
  "modes.split": "Velden + pagina",
@@ -2710,8 +3550,6 @@ var nl_default = {
2710
3550
  resize: "Voorbeeldpaneel aanpassen",
2711
3551
  resizeHint: "Sleep om te wijzigen; dubbelklik zet terug op de helft",
2712
3552
  scrollToHovered: "Naar het gemarkeerde blok scrollen",
2713
- 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.",
2714
- previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
2715
3553
  previewFailed: "Het voorbeeld antwoordde niet binnen 15 s. Als de frontend nog laadt, verschijnt het vanzelf; het formulier blijft bruikbaar.",
2716
3554
  previewLoading: "Voorbeeld laden\u2026",
2717
3555
  retry: "Opnieuw proberen",
@@ -2856,8 +3694,13 @@ var nl_default = {
2856
3694
  confirmDelete: "Blok {name} verwijderen?",
2857
3695
  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.",
2858
3696
  delete: "Verwijderen",
2859
- selectMode: "Blokken selecteren om te kopi\xEBren",
2860
- copySelected: "Selectie kopi\xEBren ({count})",
3697
+ selectBlocks: "Blokken selecteren",
3698
+ selectAll: "Alles selecteren",
3699
+ selectNone: "Niets selecteren",
3700
+ selectedCount: "{count} geselecteerd",
3701
+ copy: "Kopi\xEBren",
3702
+ copyNothing: "Selecteer minstens \xE9\xE9n blok om te kopi\xEBren.",
3703
+ selectDone: "Klaar",
2861
3704
  paste: "{count, plural, one {# blok} other {# blokken}} plakken",
2862
3705
  pasted: "{count, plural, one {# blok geplakt} other {# blokken geplakt}}.",
2863
3706
  copied: "{count, plural, one {# blok gekopieerd} other {# blokken gekopieerd}}. Plak ze op elke pagina van deze site.",
@@ -2920,7 +3763,120 @@ var nl_default = {
2920
3763
  historyMax: "Momentopnamen per document (maximum)",
2921
3764
  historyEventDays: "Activiteit bewaren (dagen)",
2922
3765
  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.",
2923
- historyInvalid: "Gehele getallen: 1 tot 3650 dagen (de activiteit minstens zo lang bewaard als de momentopnamen) en 1 tot 1000 momentopnamen."
3766
+ historyInvalid: "Gehele getallen: 1 tot 3650 dagen (de activiteit minstens zo lang bewaard als de momentopnamen) en 1 tot 1000 momentopnamen.",
3767
+ fieldHelp: "Meer informatie",
3768
+ paneTitle: "Werkbalk van het paginavoorbeeld",
3769
+ paneHelp: "Aangevinkte bedieningselementen staan in deze volgorde op de werkbalk van het paginavoorbeeld. Status en Opslaan/Publiceren blijven samen rechts; niet aangevinkte zijn verborgen.",
3770
+ "toolbar.modes": "Bewerkmodus",
3771
+ "toolbar.history": "Ongedaan maken en opnieuw",
3772
+ "toolbar.devices": "Menu paginabreedte",
3773
+ "toolbar.status": "Documentstatus",
3774
+ "toolbar.actions": "Opslaan en Publiceren",
3775
+ paneDevices: "Paginabreedtes",
3776
+ paneDevicesHelp: "Opties van het breedtemenu, op volgorde; de eerste geldt tot een redacteur een andere kiest. Eigen breedtes: 240 tot 3840 px.",
3777
+ paneAddWidth: "Breedte toevoegen",
3778
+ paneWidthLabel: "Label",
3779
+ paneWidth: "Breedte (px)",
3780
+ paneRemoveWidth: "Breedte verwijderen",
3781
+ 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.",
3782
+ paneTypeOverride: "Eigen werkbalk van het paginavoorbeeld voor {name}",
3783
+ add: "Blok toevoegen",
3784
+ openAll: "Alle blokken openen",
3785
+ closeAll: "Alle blokken sluiten",
3786
+ 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.",
3787
+ previewNoUrl: "Geen voorbeeld-URL: stel die in bij Instellingen, Blockscene, of configureer Strapi's native Preview voor dit contenttype.",
3788
+ selectMode: "Blokken selecteren om te kopi\xEBren",
3789
+ copySelected: "Selectie kopi\xEBren ({count})",
3790
+ trashDays: "Verwijderde documenten bewaren (dagen)",
3791
+ trashDaysHelp: "Verwijderde documenten blijven zoveel dagen in de prullenbak (vastgelegd bij elke verwijdering), daarna wist de nachtelijke taak ze.",
3792
+ "historyActions.purge": "Definitief verwijderd",
3793
+ contentMenu: "Activiteit en prullenbak",
3794
+ contentTitle: "Contentactiviteit en prullenbak",
3795
+ contentSubtitle: "Wijzigingen via Strapi (admin, API, plugins) aan de contenttypes die de versiegeschiedenis dekt.",
3796
+ contentOff: "Versiegeschiedenis staat uit: er wordt niets nieuws vastgelegd of in de prullenbak gezet. Zet hem aan in Instellingen, Blockscene.",
3797
+ contentLoading: "Laden\u2026",
3798
+ contentNone: "\u2014",
3799
+ contentUntitled: "(zonder titel)",
3800
+ contentGone: "bestaat niet meer",
3801
+ contentOpen: "Openen",
3802
+ contentPrevious: "Vorige",
3803
+ contentNext: "Volgende",
3804
+ contentPage: "Pagina {page} van {pages}, {total} in totaal",
3805
+ contentClear: "Filters wissen",
3806
+ activityTab: "Activiteit",
3807
+ activityPerson: "Persoon",
3808
+ activityAnyone: "Iedereen",
3809
+ activityType: "Contenttype",
3810
+ activityAnyType: "Alle contenttypes",
3811
+ activityAction: "Actie",
3812
+ activityAnyAction: "Alle acties",
3813
+ activityFrom: "Van",
3814
+ activityTo: "Tot",
3815
+ activitySearch: "Titel bevat",
3816
+ activitySearchButton: "Zoeken",
3817
+ activityWhen: "Wanneer",
3818
+ activityDocument: "Document",
3819
+ activityWho: "Wie",
3820
+ activityWhat: "Wat",
3821
+ activityEmpty: "Geen activiteit past bij deze filters.",
3822
+ activityFailed: "De activiteit kon niet worden geladen.",
3823
+ activityRestoredFrom: "Terug uit de prullenbak",
3824
+ trashTab: "Prullenbak",
3825
+ trashShowRestored: "Herstelde items tonen",
3826
+ trashLocales: "Talen",
3827
+ trashDeletedBy: "Verwijderd door",
3828
+ trashDeletedAt: "Verwijderd",
3829
+ trashExpires: "Definitief verwijderd",
3830
+ trashExpiresIn: "over {days} dagen",
3831
+ trashExpiresToday: "vannacht",
3832
+ trashRestoredAs: "Hersteld",
3833
+ trashEmpty: "De prullenbak is leeg.",
3834
+ trashFailed: "De prullenbak kon niet worden geladen.",
3835
+ trashPreview: "Voorbeeld",
3836
+ trashRestore: "Herstellen",
3837
+ trashDelete: "Definitief verwijderen",
3838
+ trashDeleteTitle: "Definitief verwijderen",
3839
+ trashDeleteConfirm: "\u201C{title}\u201D definitief uit de prullenbak verwijderen? Daarna kan het niet meer worden hersteld. Mediabestanden worden niet verwijderd.",
3840
+ trashDeleted: "Definitief verwijderd.",
3841
+ trashDeleteFailed: "Het kon niet worden verwijderd.",
3842
+ trashDraft: "concept",
3843
+ trashPublished: "gepubliceerd",
3844
+ trashFields: "Velden",
3845
+ trashBlocks: "Blokken",
3846
+ trashItems: "{count} item(s)",
3847
+ trashIncoming: "{count} koppeling(en) vanuit andere documenten of blokken zijn bewaard.",
3848
+ trashClose: "Sluiten",
3849
+ restoreTitle: "\u201C{title}\u201D herstellen",
3850
+ restoreChecking: "Controleren wat herstellen zou doen\u2026",
3851
+ restoreIntro: "Het document komt terug als concept, met de inhoud van het concept: controleer het en publiceer het opnieuw.",
3852
+ restoreNew: "Er wordt een nieuw document gemaakt (Strapi hergebruikt de oorspronkelijke id niet).",
3853
+ restoreInto: "De talen komen terug in het bestaande document.",
3854
+ restoreLocales: "Herstelde talen: {locales}",
3855
+ restoreBlocked: "Zo kan het niet worden hersteld (er wordt niets geschreven):",
3856
+ restoreWarnings: "Het wordt hersteld met deze verschillen:",
3857
+ restoreConfirm: "Herstellen als concept",
3858
+ restoreCancel: "Annuleren",
3859
+ restoreDone: "Hersteld als concept.",
3860
+ restoreAlready: "Dit item is al hersteld.",
3861
+ restoreFailed: "Herstellen is mislukt: er is niets geschreven.",
3862
+ restoreOpen: "Het herstelde document openen",
3863
+ "report.typeGone": "Het contenttype bestaat niet meer.",
3864
+ "report.localeExists": "Het document heeft de taal {locale} weer.",
3865
+ "report.unique": "\u201C{value}\u201D wordt al gebruikt in {field} ({locale}) door een ander document.",
3866
+ "report.singleExists": "Dit single type heeft weer een document.",
3867
+ "report.nothing": "Niets te herstellen: geen van de talen is nog ingesteld.",
3868
+ "report.restored": "Al hersteld.",
3869
+ "report.published": "Er bestond een gepubliceerde versie ({locales}): die blijft in het prullenbakitem, het concept komt terug.",
3870
+ "report.localeRemoved": "De taal {locale} is niet meer ingesteld: overgeslagen.",
3871
+ "report.required": "Lege verplichte velden ({locale}): {fields}. Vul ze in voor het publiceren.",
3872
+ "report.fieldsRemoved": "Velden die het schema niet meer heeft, weggelaten ({locale}): {fields}.",
3873
+ "report.media": "{count} mediabestand(en) bestaan niet meer, leeg gelaten ({locale}).",
3874
+ "report.relations": "{count} gekoppelde document(en) bestaan niet meer, weggelaten ({locale}).",
3875
+ "report.blocks": "{count} blok(ken) waarvan de zone het component niet meer toestaat, weggelaten ({locale}).",
3876
+ "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).",
3877
+ groupCollapse: "Groep {label} inklappen",
3878
+ groupExpand: "Groep {label} uitklappen",
3879
+ groupBlocks: "{count, plural, one {# blok} other {# blokken}}"
2924
3880
  };
2925
3881
 
2926
3882
  // admin/messages.ts
@@ -3092,11 +4048,10 @@ function RowPreviews({ zones, components, catalog, Modal: Modal2 }) {
3092
4048
  ] });
3093
4049
  }
3094
4050
 
3095
- // admin/RowActions.tsx
4051
+ // admin/GroupRows.tsx
3096
4052
  import * as React3 from "react";
3097
4053
  import { createPortal as createPortal2 } from "react-dom";
3098
- import styled2 from "styled-components";
3099
- import { Button, Flex, Typography } from "@strapi/design-system";
4054
+ import styled2, { useTheme } from "styled-components";
3100
4055
 
3101
4056
  // admin/rows.mjs
3102
4057
  var import_groups2 = __toESM(require_groups(), 1);
@@ -3140,9 +4095,9 @@ function integerKeys(rows, n) {
3140
4095
  const max = Math.max(-1, ...rows.map((row) => Number(row?.__temp_key__)).filter(Number.isFinite));
3141
4096
  return Array.from({ length: n }, (_, i) => max + 1 + i);
3142
4097
  }
3143
- var insertRows = (rows, at, items, keys) => [
4098
+ var insertRows = (rows, at, items2, keys) => [
3144
4099
  ...rows.slice(0, at),
3145
- ...items.map((item, i) => ({ ...item, __temp_key__: keys[i] })),
4100
+ ...items2.map((item, i) => ({ ...item, __temp_key__: keys[i] })),
3146
4101
  ...rows.slice(at)
3147
4102
  ];
3148
4103
  function setHidden(rows, index, groups, name, value) {
@@ -3176,6 +4131,85 @@ function pasteProblem(clip, zone, rows, components, groups) {
3176
4131
  if (groups && (0, import_groups2.validateGroups)(clip.rows, groups).length) return { code: "unbalanced" };
3177
4132
  return null;
3178
4133
  }
4134
+ function groupOutline(rows, groups) {
4135
+ const out = rows.map(() => ({ depth: 0, kind: "block", parents: [] }));
4136
+ if (!groups) return out;
4137
+ const stack = [];
4138
+ rows.forEach((row, i) => {
4139
+ const parents = stack.map((s) => s.index);
4140
+ const top = stack[stack.length - 1];
4141
+ if (top && (0, import_groups2.isClose)(row, groups) && row.__component === top.close) {
4142
+ stack.pop();
4143
+ out[top.index].end = i;
4144
+ out[top.index].count = out.slice(top.index + 1, i).filter((r) => r.kind !== "close").length;
4145
+ out[i] = { depth: parents.length, kind: "close", parents };
4146
+ return;
4147
+ }
4148
+ const open = (0, import_groups2.isOpener)(row, groups);
4149
+ out[i] = { depth: parents.length, kind: open ? "open" : "block", parents };
4150
+ if (open) stack.push({ index: i, close: groups[row.__component] });
4151
+ });
4152
+ return out;
4153
+ }
4154
+ function movedRow(prev, next, actor) {
4155
+ const n = prev.length;
4156
+ if (n !== next.length || n < 2) return null;
4157
+ const k = prev.map(import_groups2.blockKey), m = next.map(import_groups2.blockKey);
4158
+ let i = 0;
4159
+ while (i < n && k[i] === m[i]) i++;
4160
+ if (i === n) return null;
4161
+ let j = n - 1;
4162
+ while (k[j] === m[j]) j--;
4163
+ const same = (a, b) => (0, import_groups2.blockKey)(a) === (0, import_groups2.blockKey)(b) || a?.id == null && b?.id == null && a?.__component === b?.__component;
4164
+ const shifted = (from, to, by) => {
4165
+ for (let x = from; x <= to; x++) if (m[x] !== k[x + by]) return false;
4166
+ return true;
4167
+ };
4168
+ const down = same(prev[i], next[j]) && shifted(i, j - 1, 1);
4169
+ const up = same(prev[j], next[i]) && shifted(i + 1, j, -1);
4170
+ if (down && up) return actor === k[i] ? { from: i, to: j } : actor === k[j] ? { from: j, to: i } : null;
4171
+ return down ? { from: i, to: j } : up ? { from: j, to: i } : null;
4172
+ }
4173
+ function keepGroupsTogether(prev, next, groups, actor) {
4174
+ if (!groups) return null;
4175
+ const move = movedRow(prev, next, actor);
4176
+ if (!move || !(0, import_groups2.isOpener)(prev[move.from], groups)) return null;
4177
+ const start = move.from, end = groupOutline(prev, groups)[start].end;
4178
+ if (end == null) return null;
4179
+ const members = new Set(prev.slice(start + 1, end + 1).map(import_groups2.blockKey));
4180
+ const at = move.to;
4181
+ if (at > 0 && members.has((0, import_groups2.blockKey)(next[at - 1]))) {
4182
+ if (end + 1 >= prev.length) return prev.slice();
4183
+ const rest = [...prev.slice(0, start), ...prev.slice(end + 1)];
4184
+ return [...rest.slice(0, start + 1), ...prev.slice(start, end + 1), ...rest.slice(start + 1)];
4185
+ }
4186
+ const others = next.filter((row) => !members.has((0, import_groups2.blockKey)(row)));
4187
+ const o = others.indexOf(next[at]);
4188
+ return [...others.slice(0, o + 1), ...next.filter((row) => members.has((0, import_groups2.blockKey)(row))), ...others.slice(o + 1)];
4189
+ }
4190
+ function errorRows(errors, zone) {
4191
+ const out = /* @__PURE__ */ new Set();
4192
+ const nested = errors?.[zone];
4193
+ if (nested && typeof nested === "object") {
4194
+ for (const [key, value] of Object.entries(nested)) if (value && /^\d+$/.test(key)) out.add(Number(key));
4195
+ }
4196
+ for (const key of Object.keys(errors || {})) {
4197
+ const hit = key.startsWith(`${zone}.`) && /^(\d+)(\.|$)/.exec(key.slice(zone.length + 1));
4198
+ if (hit) out.add(Number(hit[1]));
4199
+ }
4200
+ return [...out];
4201
+ }
4202
+
4203
+ // admin/history.mjs
4204
+ var drag = { id: 0, open: false, until: 0 };
4205
+ var startDrag = () => {
4206
+ drag.id++;
4207
+ drag.open = true;
4208
+ };
4209
+ var endDrag = (now = Date.now(), settle = 400) => {
4210
+ drag.open = false;
4211
+ drag.until = now + settle;
4212
+ };
3179
4213
 
3180
4214
  // admin/icons.tsx
3181
4215
  import styled from "styled-components";
@@ -3222,8 +4256,11 @@ var PATHS = {
3222
4256
  duplicate: "M8 8h12v12H8zM4 16V4h12",
3223
4257
  clipboard: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2",
3224
4258
  paste: "M9 3h6v3H9zM7 4.5H5v16h14v-16h-2M12 10v7M9 14l3 3 3-3",
3225
- select: "M4 4h16v16H4zM8 12l3 3 5-6"
4259
+ select: "M4 4h16v16H4zM8 12l3 3 5-6",
4260
+ // Zone bar: the "…" menu.
4261
+ 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"
3226
4262
  };
4263
+ var ICON_NAMES = Object.keys(PATHS);
3227
4264
  function Icon({ name, size = 18, filled }) {
3228
4265
  const d = PATHS[name];
3229
4266
  if (!d) return null;
@@ -3240,9 +4277,234 @@ var ToolButton = styled.button`
3240
4277
  `;
3241
4278
  var Tool = ({ icon, label, active, ...rest }) => /* @__PURE__ */ jsx3(ToolButton, { type: "button", "aria-label": label, title: label, $active: active, ...active !== void 0 ? { "aria-pressed": active } : {}, ...rest, children: /* @__PURE__ */ jsx3(Icon, { name: icon }) });
3242
4279
 
3243
- // admin/RowActions.tsx
4280
+ // admin/GroupRows.tsx
3244
4281
  import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
4282
+ var DEPTH = "data-blockscene-depth";
4283
+ var KIND = "data-blockscene-group";
4284
+ var FOLD = "data-blockscene-fold";
4285
+ var COUNT = "data-blockscene-fold-count";
4286
+ var STEP = "2.4rem";
4287
+ var folded = /* @__PURE__ */ new Set();
4288
+ var set = (el, name, value) => {
4289
+ if (value === null) el.hasAttribute(name) && el.removeAttribute(name);
4290
+ else if (el.getAttribute(name) !== value) el.setAttribute(name, value);
4291
+ };
4292
+ var items = (list) => [...list.querySelectorAll(":scope > li")];
4293
+ var Fold = styled2.span`
4294
+ display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 28px; height: 28px; margin-left: 8px;
4295
+ border-radius: 4px; cursor: pointer; color: ${({ theme }) => theme.colors.primary600};
4296
+ background: ${({ theme, $open }) => $open ? "transparent" : theme.colors.primary100};
4297
+ &:hover { background: ${({ theme }) => theme.colors.primary100}; }
4298
+ &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: -2px; }
4299
+ > span { display: inline-flex; transition: transform 120ms; transform: rotate(${({ $open }) => $open ? "0" : "-90deg"}); }
4300
+ `;
4301
+ var Count = styled2.span`
4302
+ margin-right: 4px; padding: 1px 6px; border-radius: 3px; font-size: 11px; font-weight: 600; line-height: 16px; white-space: nowrap;
4303
+ color: ${({ theme }) => theme.colors.primary700}; background: ${({ theme }) => theme.colors.primary100};
4304
+ `;
4305
+ function GroupRows({ zones, form, groups, docKey, labelOf }) {
4306
+ const t = useMessages();
4307
+ const theme = useTheme();
4308
+ const on = Boolean(groups && form);
4309
+ const [anchors, setAnchors] = React3.useState([]);
4310
+ const [, settle] = React3.useReducer((n) => n + 1, 0);
4311
+ const settled = React3.useRef(/* @__PURE__ */ new Map());
4312
+ const actor = React3.useRef(null);
4313
+ const landed = React3.useRef(null);
4314
+ const dragging = React3.useRef(false);
4315
+ const previewed = React3.useRef(false);
4316
+ const end = React3.useRef(() => {
4317
+ if (!dragging.current) return;
4318
+ dragging.current = previewed.current = false;
4319
+ endDrag();
4320
+ settle();
4321
+ }).current;
4322
+ const latest = React3.useRef({ zones, form, docKey, labelOf });
4323
+ latest.current = { zones, form, docKey, labelOf };
4324
+ React3.useEffect(() => settled.current.clear(), [docKey]);
4325
+ React3.useEffect(() => {
4326
+ if (!on || dragging.current) return;
4327
+ for (const zone of zones) {
4328
+ const rows = form.rows(zone.name);
4329
+ const prev = settled.current.get(zone.name);
4330
+ settled.current.set(zone.name, rows);
4331
+ if (!prev || prev === rows) continue;
4332
+ const move = movedRow(prev, rows, actor.current);
4333
+ if (move) landed.current = { zone: zone.name, key: blockKey(rows[move.to]) };
4334
+ const next = keepGroupsTogether(prev, rows, groups, actor.current);
4335
+ if (next) {
4336
+ settled.current.set(zone.name, next);
4337
+ form.setRows(zone.name, next);
4338
+ }
4339
+ }
4340
+ });
4341
+ React3.useEffect(() => {
4342
+ if (!on) return;
4343
+ const rowKey = (target) => {
4344
+ const li = target?.closest?.("ol[aria-describedby] > li");
4345
+ if (!li) return null;
4346
+ for (const zone of latest.current.zones) {
4347
+ const list2 = findZoneList(zone.label);
4348
+ if (li.parentElement === list2) return blockKey(latest.current.form.rows(zone.name)[items(list2).indexOf(li)]) || null;
4349
+ }
4350
+ return null;
4351
+ };
4352
+ const act = (event) => {
4353
+ actor.current = event.metaKey || event.ctrlKey || event.altKey ? null : rowKey(event.target);
4354
+ };
4355
+ const start = (event) => {
4356
+ if (!rowKey(event.target)) return;
4357
+ dragging.current = true;
4358
+ startDrag();
4359
+ };
4360
+ const ends = ["drop", "dragend", "mousemove", "pointerdown", "keydown"];
4361
+ document.addEventListener("pointerdown", act, true);
4362
+ document.addEventListener("keydown", act, true);
4363
+ document.addEventListener("dragstart", start, true);
4364
+ for (const type of ends) window.addEventListener(type, end, true);
4365
+ return () => {
4366
+ document.removeEventListener("pointerdown", act, true);
4367
+ document.removeEventListener("keydown", act, true);
4368
+ document.removeEventListener("dragstart", start, true);
4369
+ for (const type of ends) window.removeEventListener(type, end, true);
4370
+ };
4371
+ }, [on]);
4372
+ const sync = React3.useRef(() => {
4373
+ });
4374
+ sync.current = () => {
4375
+ const { zones: zones2, form: form2, docKey: docKey2, labelOf: labelOf2 } = latest.current;
4376
+ if (dragging.current) {
4377
+ const placeholder = zones2.some((zone) => {
4378
+ const list2 = findZoneList(zone.label);
4379
+ return list2 && items(list2).some((li) => !li.querySelector("button[aria-expanded]"));
4380
+ });
4381
+ if (placeholder) previewed.current = true;
4382
+ else if (previewed.current) end();
4383
+ return;
4384
+ }
4385
+ const next = [];
4386
+ const seen = /* @__PURE__ */ new Set();
4387
+ if (on)
4388
+ for (const zone of zones2) {
4389
+ const list2 = zone.count ? findZoneList(zone.label) : null;
4390
+ const rows = form2.rows(zone.name);
4391
+ const lis = list2 ? items(list2) : [];
4392
+ if (!list2 || lis.length !== rows.length) continue;
4393
+ const outline = groupOutline(rows, groups);
4394
+ const idOf = (i) => `${docKey2}|${zone.name}|${blockKey(rows[i])}`;
4395
+ const unfold = [...form2.errorRows?.(zone.name) || []];
4396
+ if (landed.current?.zone === zone.name) unfold.push(rows.findIndex((row) => blockKey(row) === landed.current?.key));
4397
+ for (const index of unfold) for (const p of outline[index]?.parents || []) folded.delete(idOf(p));
4398
+ const isFolded = (i) => outline[i].end != null && folded.has(idOf(i));
4399
+ lis.forEach((li, i) => {
4400
+ const o = outline[i];
4401
+ seen.add(li);
4402
+ set(li, DEPTH, o.depth ? String(o.depth) : null);
4403
+ if (o.depth) li.style.setProperty("--bs-depth", String(o.depth));
4404
+ set(li, KIND, o.kind === "block" ? null : o.kind);
4405
+ set(li, FOLDED, o.parents.some(isFolded) ? "" : null);
4406
+ const toggle = li.querySelector("button[aria-expanded]");
4407
+ if (o.kind !== "open" || o.end == null || !toggle?.parentElement) return;
4408
+ let el = toggle.parentElement.querySelector(`:scope > [${FOLD}]`);
4409
+ if (!el) {
4410
+ el = document.createElement("span");
4411
+ el.setAttribute(FOLD, "");
4412
+ el.style.cssText = "display:inline-flex;align-items:center";
4413
+ toggle.parentElement.insertBefore(el, toggle);
4414
+ }
4415
+ const actions = toggle.nextElementSibling;
4416
+ let countEl = actions?.querySelector(`:scope > [${COUNT}]`) || null;
4417
+ if (actions && !countEl) {
4418
+ countEl = document.createElement("span");
4419
+ countEl.setAttribute(COUNT, "");
4420
+ countEl.style.cssText = "display:inline-flex;align-items:center";
4421
+ actions.insertBefore(countEl, actions.firstChild);
4422
+ }
4423
+ next.push({ el, countEl, zone: zone.name, index: i, id: idOf(i), count: o.count || 0, open: !isFolded(i), label: labelOf2(rows[i]) });
4424
+ });
4425
+ }
4426
+ landed.current = null;
4427
+ for (const li of document.querySelectorAll(`li[${DEPTH}], li[${KIND}], li[${FOLDED}]`))
4428
+ if (!seen.has(li)) for (const name of [DEPTH, KIND, FOLDED]) li.removeAttribute(name);
4429
+ for (const el of document.querySelectorAll(`[${FOLD}], [${COUNT}]`)) if (!next.some((a) => a.el === el || a.countEl === el)) el.remove();
4430
+ setAnchors(
4431
+ (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
4432
+ );
4433
+ };
4434
+ React3.useEffect(() => {
4435
+ sync.current();
4436
+ });
4437
+ React3.useEffect(() => {
4438
+ let frame2 = 0;
4439
+ const observer = new MutationObserver(() => {
4440
+ if (!frame2) frame2 = requestAnimationFrame(() => {
4441
+ frame2 = 0;
4442
+ sync.current();
4443
+ });
4444
+ });
4445
+ observer.observe(document.body, { childList: true, subtree: true });
4446
+ return () => {
4447
+ observer.disconnect();
4448
+ cancelAnimationFrame(frame2);
4449
+ for (const el of document.querySelectorAll(`[${FOLD}], [${COUNT}]`)) el.remove();
4450
+ for (const li of document.querySelectorAll(`li[${DEPTH}], li[${KIND}], li[${FOLDED}]`)) for (const name of [DEPTH, KIND, FOLDED]) li.removeAttribute(name);
4451
+ };
4452
+ }, []);
4453
+ if (!on) return null;
4454
+ const flip2 = (id) => {
4455
+ if (folded.has(id)) folded.delete(id);
4456
+ else folded.add(id);
4457
+ sync.current();
4458
+ };
4459
+ const line = theme?.colors?.primary600 || "#4945ff";
4460
+ const list = "ol[aria-describedby] > li";
4461
+ return /* @__PURE__ */ jsxs2(Fragment2, { children: [
4462
+ /* @__PURE__ */ jsx4("style", { children: `
4463
+ ${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; }
4464
+ ${list}[${FOLDED}] { display: none !important; }
4465
+ ${list}[${KIND}="close"] [data-handler-id] { display: none !important; }
4466
+ ${list}[${KIND}="close"] button[aria-expanded]:first-of-type { min-height: 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; opacity: 0.7; }
4467
+ ${list}[${KIND}="close"] button[aria-expanded]:first-of-type + * { padding-top: 0 !important; padding-bottom: 0 !important; }
4468
+ ${list}[${KIND}="close"] button[aria-expanded] [data-blockscene-row-thumb] { display: none; }` }),
4469
+ anchors.map(
4470
+ (a) => createPortal2(
4471
+ /* @__PURE__ */ jsx4(
4472
+ Fold,
4473
+ {
4474
+ role: "button",
4475
+ tabIndex: 0,
4476
+ $open: a.open,
4477
+ "aria-expanded": a.open,
4478
+ "data-testid": `group-fold-${a.zone}-${a.index}`,
4479
+ title: t.f(a.open ? "groupCollapse" : "groupExpand", { label: a.label }),
4480
+ "aria-label": t.f(a.open ? "groupCollapse" : "groupExpand", { label: a.label }),
4481
+ onClick: () => flip2(a.id),
4482
+ onKeyDown: (event) => {
4483
+ if (event.key !== "Enter" && event.key !== " ") return;
4484
+ event.preventDefault();
4485
+ flip2(a.id);
4486
+ },
4487
+ children: /* @__PURE__ */ jsx4("span", { children: /* @__PURE__ */ jsx4(Icon, { name: "chevron", size: 16 }) })
4488
+ }
4489
+ ),
4490
+ a.el,
4491
+ `fold:${a.zone}:${a.index}`
4492
+ )
4493
+ ),
4494
+ anchors.map(
4495
+ (a) => !a.open && a.countEl ? createPortal2(/* @__PURE__ */ jsx4(Count, { "data-testid": `group-count-${a.zone}-${a.index}`, children: t.f("groupBlocks", { count: a.count }) }), a.countEl, `count:${a.zone}:${a.index}`) : null
4496
+ )
4497
+ ] });
4498
+ }
4499
+
4500
+ // admin/RowActions.tsx
4501
+ import * as React4 from "react";
4502
+ import { createPortal as createPortal3 } from "react-dom";
4503
+ import styled3 from "styled-components";
4504
+ import { Button, Flex, Typography } from "@strapi/design-system";
4505
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
3245
4506
  var ATTR2 = "data-blockscene-row-actions";
4507
+ var SELECT_ATTR = "data-blockscene-row-select";
3246
4508
  var HIDDEN_ATTR = "data-blockscene-hidden";
3247
4509
  var CLIP_EVENT = "blockscene:clipboard";
3248
4510
  var storage = () => {
@@ -3253,8 +4515,8 @@ var storage = () => {
3253
4515
  }
3254
4516
  };
3255
4517
  function useClipboard() {
3256
- const [clip, setClip] = React3.useState(() => readClip(storage()));
3257
- React3.useEffect(() => {
4518
+ const [clip, setClip] = React4.useState(() => readClip(storage()));
4519
+ React4.useEffect(() => {
3258
4520
  const sync = (event) => {
3259
4521
  if (!event?.key || event.key === CLIPBOARD_KEY) setClip(readClip(storage()));
3260
4522
  };
@@ -3289,16 +4551,16 @@ function pasteInto(form, zone, clip, components, groups, t, at) {
3289
4551
  }
3290
4552
  var actionsOf = (toggle) => toggle.nextElementSibling;
3291
4553
  var trashOf = (toggle) => [...actionsOf(toggle)?.querySelectorAll("button") || []].find((b) => !b.closest(`[${ATTR2}]`)) || null;
3292
- function useAnchors2(zones, enabled) {
3293
- const [anchors, setAnchors] = React3.useState([]);
3294
- const latest = React3.useRef(zones);
3295
- latest.current = zones;
3296
- const sync = React3.useRef(() => {
4554
+ function useAnchors2(zones, enabled, selecting) {
4555
+ const [anchors, setAnchors] = React4.useState([]);
4556
+ const latest = React4.useRef({ zones, selecting });
4557
+ latest.current = { zones, selecting };
4558
+ const sync = React4.useRef(() => {
3297
4559
  });
3298
4560
  sync.current = () => {
3299
4561
  const next = [];
3300
4562
  if (enabled)
3301
- for (const zone of latest.current) {
4563
+ for (const zone of latest.current.zones) {
3302
4564
  const list = zone.count ? findZoneList(zone.label) : null;
3303
4565
  if (!list) continue;
3304
4566
  toggles(list).forEach((toggle, index) => {
@@ -3312,18 +4574,29 @@ function useAnchors2(zones, enabled) {
3312
4574
  el.style.cssText = "display:inline-flex;align-items:center";
3313
4575
  holder.parentElement?.insertBefore(el, holder);
3314
4576
  }
3315
- next.push({ el, zone: zone.name, index });
4577
+ let select = null;
4578
+ if (latest.current.selecting === zone.name && toggle.parentElement) {
4579
+ select = toggle.parentElement.querySelector(`:scope > [${SELECT_ATTR}]`);
4580
+ if (!select) {
4581
+ select = document.createElement("span");
4582
+ select.setAttribute(SELECT_ATTR, "");
4583
+ select.style.cssText = "display:inline-flex;align-items:center;padding-left:12px";
4584
+ toggle.parentElement.insertBefore(select, toggle);
4585
+ }
4586
+ }
4587
+ next.push({ el, select, zone: zone.name, index });
3316
4588
  });
3317
4589
  }
3318
- for (const el of document.querySelectorAll(`[${ATTR2}]`)) if (!next.some((a) => a.el === el)) el.remove();
4590
+ for (const attr of [ATTR2, SELECT_ATTR])
4591
+ for (const el of document.querySelectorAll(`[${attr}]`)) if (!next.some((a) => a.el === el || a.select === el)) el.remove();
3319
4592
  setAnchors(
3320
- (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
4593
+ (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
3321
4594
  );
3322
4595
  };
3323
- React3.useEffect(() => {
4596
+ React4.useEffect(() => {
3324
4597
  sync.current();
3325
4598
  });
3326
- React3.useEffect(() => {
4599
+ React4.useEffect(() => {
3327
4600
  let frame2 = 0;
3328
4601
  const observer = new MutationObserver(() => {
3329
4602
  if (!frame2) frame2 = requestAnimationFrame(() => {
@@ -3335,7 +4608,7 @@ function useAnchors2(zones, enabled) {
3335
4608
  return () => {
3336
4609
  observer.disconnect();
3337
4610
  cancelAnimationFrame(frame2);
3338
- for (const el of document.querySelectorAll(`[${ATTR2}]`)) el.remove();
4611
+ for (const el of document.querySelectorAll(`[${ATTR2}], [${SELECT_ATTR}]`)) el.remove();
3339
4612
  for (const el of document.querySelectorAll(`[${HIDDEN_ATTR}]`)) el.removeAttribute(HIDDEN_ATTR);
3340
4613
  };
3341
4614
  }, []);
@@ -3344,8 +4617,16 @@ function useAnchors2(zones, enabled) {
3344
4617
  function useRowActions({ zones, components, catalog, form }) {
3345
4618
  const t = useMessages();
3346
4619
  const clip = useClipboard();
3347
- const [selection, setSelection] = React3.useState(null);
3348
- const [busy, setBusy] = React3.useState(false);
4620
+ const [selection, setSelection] = React4.useState(null);
4621
+ const [busy, setBusy] = React4.useState(false);
4622
+ React4.useEffect(() => {
4623
+ if (!selection) return;
4624
+ const onKey = (event) => {
4625
+ if (event.key === "Escape" && !event.defaultPrevented && !document.querySelector('[role="dialog"]')) setSelection(null);
4626
+ };
4627
+ document.addEventListener("keydown", onKey);
4628
+ return () => document.removeEventListener("keydown", onKey);
4629
+ }, [Boolean(selection)]);
3349
4630
  if (!form) return null;
3350
4631
  const editor = catalog?.editor || {};
3351
4632
  const groups = catalog?.groups || null;
@@ -3369,30 +4650,32 @@ function useRowActions({ zones, components, catalog, form }) {
3369
4650
  const key = blockKey(rows[index]);
3370
4651
  const [start, end] = actionRange(rows, index, groups);
3371
4652
  if (rows.length + end - start + 1 > (zone?.max ?? Infinity)) return form.notify("warning", t.zoneFull);
3372
- const items = await form.prepare(rows.slice(start, end + 1));
4653
+ const items2 = await form.prepare(rows.slice(start, end + 1));
3373
4654
  const now = form.rows(zoneName);
3374
4655
  const at = now.findIndex((row) => blockKey(row) === key);
3375
4656
  if (at < 0) return;
3376
4657
  const after = actionRange(now, at, groups)[1] + 1;
3377
- form.setRows(zoneName, insertRows(now, after, items, form.keys(now, after, items.length)));
4658
+ form.setRows(zoneName, insertRows(now, after, items2, form.keys(now, after, items2.length)));
3378
4659
  });
3379
4660
  const copy2 = (zoneName, keys) => run(async () => {
3380
4661
  const rows = form.rows(zoneName);
3381
4662
  const indexes = expandSelection(rows, keys.map((key) => rows.findIndex((row) => blockKey(row) === key)), groups);
3382
4663
  if (!indexes.length) return;
3383
- const items = await form.prepare(indexes.map((i) => rows[i]));
3384
- if (!storeClip({ rows: items, model: form.model, locale: form.locale, zone: zoneName })) return form.notify("warning", t.copyFailed);
4664
+ const items2 = await form.prepare(indexes.map((i) => rows[i]));
4665
+ if (!storeClip({ rows: items2, model: form.model, locale: form.locale, zone: zoneName })) return form.notify("warning", t.copyFailed);
3385
4666
  setSelection(null);
3386
- form.notify("success", t.f("copied", { count: items.length }));
4667
+ form.notify("success", t.f("copied", { count: items2.length }));
3387
4668
  });
3388
4669
  const toggleHidden = (zoneName, index) => {
3389
4670
  const rows = form.rows(zoneName);
3390
4671
  if (hiddenName) form.setRows(zoneName, setHidden(rows, index, groups, hiddenName, rows[index]?.[hiddenName] !== true));
3391
4672
  };
3392
4673
  const paste = (zoneName, at) => pasteInto(form, zoneOf(zoneName), clip, components, groups, t, at);
3393
- return { t, editor, groups, hiddenName, clip, selection, setSelection, busy, form, labelOf, duplicate, copy: copy2, toggleHidden, paste, isMarker: (row) => isGroupMarker(row, groups) };
4674
+ const pastable = (zoneName) => !["empty", "notAllowed"].includes(pasteProblem(clip, zoneOf(zoneName), form.rows(zoneName), components, groups)?.code);
4675
+ const selectable = (zoneName) => form.rows(zoneName).filter((row) => canAct(row, groups)).map((row) => blockKey(row)).filter(Boolean);
4676
+ return { t, editor, groups, hiddenName, clip, selection, setSelection, busy, form, labelOf, duplicate, copy: copy2, toggleHidden, paste, pastable, selectable, isMarker: (row) => isGroupMarker(row, groups) };
3394
4677
  }
3395
- var RowButton = styled2.button`
4678
+ var RowButton = styled3.button`
3396
4679
  display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; border: 0;
3397
4680
  border-radius: 4px; cursor: pointer; background: transparent;
3398
4681
  color: ${({ theme, $on }) => $on ? theme.colors.warning600 : theme.colors.neutral500};
@@ -3400,7 +4683,7 @@ var RowButton = styled2.button`
3400
4683
  &:disabled { opacity: 0.4; cursor: default; }
3401
4684
  &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: -2px; }
3402
4685
  `;
3403
- var HiddenBadge = styled2.span`
4686
+ var HiddenBadge = styled3.span`
3404
4687
  margin-right: 4px; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; line-height: 16px;
3405
4688
  text-transform: uppercase; letter-spacing: 0.04em;
3406
4689
  color: ${({ theme }) => theme.colors.warning700}; background: ${({ theme }) => theme.colors.warning100};
@@ -3408,12 +4691,12 @@ var HiddenBadge = styled2.span`
3408
4691
  function RowActions({ zones, actions, Modal: Modal2 }) {
3409
4692
  const a = actions;
3410
4693
  const e = a?.editor || {};
3411
- const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection));
3412
- const [confirm, setConfirm] = React3.useState(null);
3413
- const bypass = React3.useRef(false);
3414
- const latest = React3.useRef({ zones, a });
4694
+ const anchors = useAnchors2(zones, Boolean(a) && Boolean(a.hiddenName || e.duplicate !== false || e.clipboard !== false || a.selection), a?.selection?.zone || null);
4695
+ const [confirm, setConfirm] = React4.useState(null);
4696
+ const bypass = React4.useRef(false);
4697
+ const latest = React4.useRef({ zones, a });
3415
4698
  latest.current = { zones, a };
3416
- React3.useEffect(() => {
4699
+ React4.useEffect(() => {
3417
4700
  if (!a || e.confirmDelete === false) return;
3418
4701
  const onClick = (event) => {
3419
4702
  const button = event.target?.closest?.("button");
@@ -3434,7 +4717,7 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3434
4717
  document.addEventListener("click", onClick, true);
3435
4718
  return () => document.removeEventListener("click", onClick, true);
3436
4719
  }, [Boolean(a), e.confirmDelete]);
3437
- React3.useEffect(() => {
4720
+ React4.useEffect(() => {
3438
4721
  if (!a) return;
3439
4722
  for (const { el, zone, index } of anchors) {
3440
4723
  const li = el.closest("li");
@@ -3455,8 +4738,29 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3455
4738
  bypass.current = false;
3456
4739
  }
3457
4740
  };
3458
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
3459
- /* @__PURE__ */ jsx4("style", { children: `li[${HIDDEN_ATTR}] button[aria-expanded] { opacity: 0.5; }` }),
4741
+ return /* @__PURE__ */ jsxs3(Fragment3, { children: [
4742
+ /* @__PURE__ */ jsx5("style", { children: `li[${HIDDEN_ATTR}] button[aria-expanded] { opacity: 0.5; }` }),
4743
+ anchors.map(({ select, zone, index }) => {
4744
+ const row = a.form.rows(zone)[index];
4745
+ const key = blockKey(row) || "";
4746
+ if (!select || !row || !canAct(row, a.groups) || a.selection?.zone !== zone) return null;
4747
+ const label = a.labelOf(row);
4748
+ return createPortal3(
4749
+ /* @__PURE__ */ jsx5(
4750
+ "input",
4751
+ {
4752
+ type: "checkbox",
4753
+ "aria-label": t.f("selectBlock", { label }),
4754
+ "data-testid": `row-select-${zone}-${index}`,
4755
+ style: { margin: 0, width: 16, height: 16, cursor: "pointer" },
4756
+ checked: a.selection.keys.includes(key),
4757
+ onChange: (event) => a.setSelection({ zone, keys: event.target.checked ? [...a.selection.keys, key] : a.selection.keys.filter((k) => k !== key) })
4758
+ }
4759
+ ),
4760
+ select,
4761
+ `select:${zone}:${index}`
4762
+ );
4763
+ }),
3460
4764
  anchors.map(({ el, zone, index }) => {
3461
4765
  const row = a.form.rows(zone)[index];
3462
4766
  if (!row) return null;
@@ -3464,22 +4768,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3464
4768
  const acts = canAct(row, a.groups);
3465
4769
  const hidden = Boolean(a.hiddenName) && row[a.hiddenName] === true;
3466
4770
  const key = blockKey(row) || "";
3467
- const selecting = a.selection?.zone === zone;
3468
- return createPortal2(
3469
- /* @__PURE__ */ jsxs2(Flex, { gap: 0, alignItems: "center", "data-testid": `row-actions-${zone}-${index}`, role: "group", "aria-label": t.f("rowActions", { label }), children: [
3470
- selecting && acts && /* @__PURE__ */ jsx4(
3471
- "input",
3472
- {
3473
- type: "checkbox",
3474
- "aria-label": t.f("selectBlock", { label }),
3475
- "data-testid": `row-select-${zone}-${index}`,
3476
- style: { margin: "0 8px", width: 16, height: 16 },
3477
- checked: a.selection.keys.includes(key),
3478
- onChange: (event) => a.setSelection({ zone, keys: event.target.checked ? [...a.selection.keys, key] : a.selection.keys.filter((k) => k !== key) })
3479
- }
3480
- ),
3481
- hidden && /* @__PURE__ */ jsx4(HiddenBadge, { "data-testid": `row-hidden-${zone}-${index}`, children: t.hiddenBadge }),
3482
- a.hiddenName && (acts || hidden) && /* @__PURE__ */ jsx4(
4771
+ return createPortal3(
4772
+ /* @__PURE__ */ jsxs3(Flex, { gap: 0, alignItems: "center", "data-testid": `row-actions-${zone}-${index}`, role: "group", "aria-label": t.f("rowActions", { label }), children: [
4773
+ hidden && /* @__PURE__ */ jsx5(HiddenBadge, { "data-testid": `row-hidden-${zone}-${index}`, children: t.hiddenBadge }),
4774
+ a.hiddenName && (acts || hidden) && /* @__PURE__ */ jsx5(
3483
4775
  RowButton,
3484
4776
  {
3485
4777
  type: "button",
@@ -3489,10 +4781,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3489
4781
  "aria-label": t.f(hidden ? "showBlock" : "hideBlock", { label }),
3490
4782
  "data-testid": `row-hide-${zone}-${index}`,
3491
4783
  onClick: () => a.toggleHidden(zone, index),
3492
- children: /* @__PURE__ */ jsx4(Icon, { name: hidden ? "eyeOff" : "eye" })
4784
+ children: /* @__PURE__ */ jsx5(Icon, { name: hidden ? "eyeOff" : "eye" })
3493
4785
  }
3494
4786
  ),
3495
- e.duplicate !== false && acts && /* @__PURE__ */ jsx4(
4787
+ e.duplicate !== false && acts && /* @__PURE__ */ jsx5(
3496
4788
  RowButton,
3497
4789
  {
3498
4790
  type: "button",
@@ -3501,10 +4793,10 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3501
4793
  "aria-label": t.f("duplicateBlock", { label }),
3502
4794
  "data-testid": `row-duplicate-${zone}-${index}`,
3503
4795
  onClick: () => a.duplicate(zone, index),
3504
- children: /* @__PURE__ */ jsx4(Icon, { name: "duplicate" })
4796
+ children: /* @__PURE__ */ jsx5(Icon, { name: "duplicate" })
3505
4797
  }
3506
4798
  ),
3507
- e.clipboard !== false && acts && /* @__PURE__ */ jsx4(
4799
+ e.clipboard !== false && acts && /* @__PURE__ */ jsx5(
3508
4800
  RowButton,
3509
4801
  {
3510
4802
  type: "button",
@@ -3513,7 +4805,7 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3513
4805
  "aria-label": t.f("copyBlock", { label }),
3514
4806
  "data-testid": `row-copy-${zone}-${index}`,
3515
4807
  onClick: () => a.copy(zone, [key]),
3516
- children: /* @__PURE__ */ jsx4(Icon, { name: "clipboard" })
4808
+ children: /* @__PURE__ */ jsx5(Icon, { name: "clipboard" })
3517
4809
  }
3518
4810
  )
3519
4811
  ] }),
@@ -3521,40 +4813,70 @@ function RowActions({ zones, actions, Modal: Modal2 }) {
3521
4813
  `${zone}:${index}`
3522
4814
  );
3523
4815
  }),
3524
- confirm && /* @__PURE__ */ jsx4(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ jsxs2(Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
3525
- /* @__PURE__ */ jsx4(Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
3526
- confirm.marker && /* @__PURE__ */ jsx4(Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
3527
- /* @__PURE__ */ jsxs2(Flex, { gap: 2, justifyContent: "flex-end", children: [
3528
- /* @__PURE__ */ jsx4(Button, { variant: "tertiary", onClick: () => setConfirm(null), "data-testid": "row-confirm-cancel", children: t.cancel }),
3529
- /* @__PURE__ */ jsx4(Button, { variant: "danger", onClick: confirmDelete, "data-testid": "row-confirm-ok", children: t.delete })
4816
+ confirm && /* @__PURE__ */ jsx5(Modal2, { open: true, width: "48rem", onOpenChange: (open) => !open && setConfirm(null), trigger: null, title: t.confirmDeleteTitle, children: /* @__PURE__ */ jsxs3(Flex, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-confirm-delete", children: [
4817
+ /* @__PURE__ */ jsx5(Typography, { children: t.f("confirmDelete", { name: confirm.label }) }),
4818
+ confirm.marker && /* @__PURE__ */ jsx5(Typography, { variant: "pi", textColor: "neutral600", children: t.confirmDeleteMarker }),
4819
+ /* @__PURE__ */ jsxs3(Flex, { gap: 2, justifyContent: "flex-end", children: [
4820
+ /* @__PURE__ */ jsx5(Button, { variant: "tertiary", onClick: () => setConfirm(null), "data-testid": "row-confirm-cancel", children: t.cancel }),
4821
+ /* @__PURE__ */ jsx5(Button, { variant: "danger", onClick: confirmDelete, "data-testid": "row-confirm-ok", children: t.delete })
3530
4822
  ] })
3531
4823
  ] }) })
3532
4824
  ] });
3533
4825
  }
3534
- function ZoneRowTools({ zone, actions: a }) {
3535
- if (!a || a.editor.clipboard === false) return null;
4826
+ function zoneMenuItems(zone, a) {
4827
+ if (!a || a.editor.clipboard === false) return [];
3536
4828
  const { t } = a;
3537
- const selecting = a.selection?.zone === zone.name;
3538
- const count = selecting ? a.selection.keys.length : 0;
3539
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
3540
- zone.count > 0 && /* @__PURE__ */ jsx4(
3541
- Tool,
4829
+ return [
4830
+ zone.count > 0 && { label: t.selectBlocks, icon: "select", testid: `zone-select-${zone.name}`, onSelect: () => a.setSelection({ zone: zone.name, keys: [] }) },
4831
+ 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) }
4832
+ ].filter(Boolean);
4833
+ }
4834
+ function SelectionBar({ zone, actions: a }) {
4835
+ const { t } = a;
4836
+ const box = React4.useRef(null);
4837
+ const keys = a.selectable(zone.name);
4838
+ const chosen = a.selection.keys.filter((key) => keys.includes(key));
4839
+ const all = keys.length > 0 && chosen.length === keys.length;
4840
+ React4.useEffect(() => {
4841
+ if (box.current) box.current.indeterminate = chosen.length > 0 && !all;
4842
+ });
4843
+ const reason = chosen.length ? void 0 : t.copyNothing;
4844
+ return /* @__PURE__ */ jsxs3(Flex, { gap: 2, alignItems: "center", "data-testid": `zone-selection-${zone.name}`, children: [
4845
+ /* @__PURE__ */ jsxs3("label", { style: { display: "inline-flex", alignItems: "center", gap: 8, cursor: "pointer" }, children: [
4846
+ /* @__PURE__ */ jsx5(
4847
+ "input",
4848
+ {
4849
+ ref: box,
4850
+ type: "checkbox",
4851
+ checked: all,
4852
+ "aria-label": chosen.length ? t.selectNone : t.selectAll,
4853
+ "data-testid": `zone-select-all-${zone.name}`,
4854
+ style: { margin: 0, width: 16, height: 16, cursor: "pointer" },
4855
+ onChange: () => a.setSelection({ zone: zone.name, keys: chosen.length ? [] : keys })
4856
+ }
4857
+ ),
4858
+ /* @__PURE__ */ jsx5(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 })
4859
+ ] }),
4860
+ /* @__PURE__ */ jsx5("span", { title: reason, children: /* @__PURE__ */ jsx5(
4861
+ Button,
3542
4862
  {
3543
- icon: "select",
3544
- label: t.selectMode,
3545
- active: selecting,
3546
- "data-testid": `zone-select-${zone.name}`,
3547
- onClick: () => a.setSelection(selecting ? null : { zone: zone.name, keys: [] })
4863
+ size: "S",
4864
+ variant: "secondary",
4865
+ startIcon: /* @__PURE__ */ jsx5(Icon, { name: "clipboard", size: 14 }),
4866
+ disabled: !chosen.length || a.busy,
4867
+ "aria-description": reason,
4868
+ onClick: () => a.copy(zone.name, chosen),
4869
+ "data-testid": `zone-copy-${zone.name}`,
4870
+ children: t.copy
3548
4871
  }
3549
- ),
3550
- selecting && /* @__PURE__ */ jsx4(Button, { size: "S", variant: "secondary", disabled: !count || a.busy, onClick: () => a.copy(zone.name, a.selection.keys), "data-testid": `zone-copy-${zone.name}`, children: t.f("copySelected", { count }) }),
3551
- a.clip && !zone.full && /* @__PURE__ */ jsx4(Button, { size: "S", variant: "secondary", startIcon: /* @__PURE__ */ jsx4(Icon, { name: "paste", size: 14 }), onClick: () => a.paste(zone.name), "data-testid": `zone-paste-${zone.name}`, children: t.f("paste", { count: a.clip.rows.length }) })
4872
+ ) }),
4873
+ /* @__PURE__ */ jsx5(Button, { size: "S", variant: "tertiary", onClick: () => a.setSelection(null), "data-testid": `zone-select-done-${zone.name}`, children: t.selectDone })
3552
4874
  ] });
3553
4875
  }
3554
4876
 
3555
4877
  // admin/Gallery.tsx
3556
- import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
3557
- var Columns = styled3.div`
4878
+ import { Fragment as Fragment5, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
4879
+ var Columns = styled4.div`
3558
4880
  column-count: ${({ $columns }) => $columns};
3559
4881
  column-gap: 12px;
3560
4882
  > * {
@@ -3563,7 +4885,7 @@ var Columns = styled3.div`
3563
4885
  margin-bottom: 12px;
3564
4886
  }
3565
4887
  `;
3566
- var Tile = styled3.button`
4888
+ var Tile = styled4.button`
3567
4889
  display: flex;
3568
4890
  flex-direction: column;
3569
4891
  gap: 8px;
@@ -3583,13 +4905,13 @@ var Tile = styled3.button`
3583
4905
  outline-offset: 2px;
3584
4906
  }
3585
4907
  `;
3586
- var Clamp = styled3(Typography2)`
4908
+ var Clamp = styled4(Typography2)`
3587
4909
  display: -webkit-box;
3588
4910
  -webkit-line-clamp: 2;
3589
4911
  -webkit-box-orient: vertical;
3590
4912
  overflow: hidden;
3591
4913
  `;
3592
- var Slider = styled3.input`
4914
+ var Slider = styled4.input`
3593
4915
  appearance: none;
3594
4916
  -webkit-appearance: none;
3595
4917
  width: 8rem;
@@ -3643,7 +4965,7 @@ var remember = (key, value) => {
3643
4965
  } catch {
3644
4966
  }
3645
4967
  };
3646
- var Frame = styled3.div`
4968
+ var Frame = styled4.div`
3647
4969
  width: 100%;
3648
4970
  overflow: hidden;
3649
4971
  border-radius: 4px;
@@ -3666,9 +4988,9 @@ function Thumb({
3666
4988
  blank
3667
4989
  }) {
3668
4990
  const key = candidates.join("|");
3669
- const [state, setState] = React4.useState({ key, index: 0 });
4991
+ const [state, setState] = React5.useState({ key, index: 0 });
3670
4992
  const index = state.key === key ? state.index : 0;
3671
- const resolved = React4.useRef("");
4993
+ const resolved = React5.useRef("");
3672
4994
  const report = (value) => {
3673
4995
  const tag = `${key}:${value}`;
3674
4996
  if (resolved.current !== tag) {
@@ -3676,11 +4998,11 @@ function Thumb({
3676
4998
  onResolved?.(value);
3677
4999
  }
3678
5000
  };
3679
- React4.useEffect(() => {
5001
+ React5.useEffect(() => {
3680
5002
  if (index >= candidates.length) report(-1);
3681
5003
  });
3682
5004
  if (index >= candidates.length)
3683
- return blank ? null : /* @__PURE__ */ jsx5(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ jsx5(
5005
+ return blank ? null : /* @__PURE__ */ jsx6(Frame, { $fixed: true, "data-thumb": "wireframe", children: /* @__PURE__ */ jsx6(
3684
5006
  Wireframe,
3685
5007
  {
3686
5008
  template,
@@ -3688,7 +5010,7 @@ function Thumb({
3688
5010
  noPreview
3689
5011
  }
3690
5012
  ) });
3691
- return /* @__PURE__ */ jsx5(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ jsx5(
5013
+ return /* @__PURE__ */ jsx6(Frame, { "data-thumb": String(index), children: /* @__PURE__ */ jsx6(
3692
5014
  "img",
3693
5015
  {
3694
5016
  src: candidates[index],
@@ -3700,12 +5022,12 @@ function Thumb({
3700
5022
  candidates[index]
3701
5023
  ) });
3702
5024
  }
3703
- var Layout = styled3.div`
5025
+ var Layout = styled4.div`
3704
5026
  display: flex;
3705
5027
  height: min(70vh, 720px);
3706
5028
  min-height: 320px;
3707
5029
  `;
3708
- var Side = styled3.nav`
5030
+ var Side = styled4.nav`
3709
5031
  flex: 0 0 ${({ $collapsed }) => $collapsed ? "48px" : "200px"};
3710
5032
  display: flex;
3711
5033
  flex-direction: column;
@@ -3715,7 +5037,7 @@ var Side = styled3.nav`
3715
5037
  border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
3716
5038
  overflow-y: auto;
3717
5039
  `;
3718
- var NavItem = styled3.button`
5040
+ var NavItem = styled4.button`
3719
5041
  display: flex;
3720
5042
  align-items: center;
3721
5043
  justify-content: ${({ $collapsed }) => $collapsed ? "center" : "flex-start"};
@@ -3747,17 +5069,17 @@ var NavItem = styled3.button`
3747
5069
  font-size: 12px;
3748
5070
  }
3749
5071
  `;
3750
- var Main = styled3.div`
5072
+ var Main = styled4.div`
3751
5073
  flex: 1;
3752
5074
  min-width: 0;
3753
5075
  display: flex;
3754
5076
  flex-direction: column;
3755
5077
  gap: 12px;
3756
5078
  `;
3757
- var Menu = styled3.div`
5079
+ var Menu = styled4.div`
3758
5080
  position: relative;
3759
5081
  `;
3760
- var MenuButton = styled3.button`
5082
+ var MenuButton = styled4.button`
3761
5083
  display: inline-flex;
3762
5084
  align-items: center;
3763
5085
  gap: 6px;
@@ -3775,7 +5097,7 @@ var MenuButton = styled3.button`
3775
5097
  outline-offset: 1px;
3776
5098
  }
3777
5099
  `;
3778
- var Popover = styled3.div`
5100
+ var Popover = styled4.div`
3779
5101
  position: absolute;
3780
5102
  top: calc(100% + 4px);
3781
5103
  left: 0;
@@ -3806,7 +5128,7 @@ var Popover = styled3.div`
3806
5128
  color: ${({ theme }) => theme.colors.neutral500};
3807
5129
  }
3808
5130
  `;
3809
- var Chip = styled3.button`
5131
+ var Chip = styled4.button`
3810
5132
  display: inline-flex;
3811
5133
  align-items: center;
3812
5134
  gap: 4px;
@@ -3818,7 +5140,7 @@ var Chip = styled3.button`
3818
5140
  color: ${({ theme }) => theme.colors.primary700};
3819
5141
  background: ${({ theme }) => theme.colors.primary100};
3820
5142
  `;
3821
- var Badge = styled3.span`
5143
+ var Badge = styled4.span`
3822
5144
  padding: 1px 6px;
3823
5145
  border-radius: 3px;
3824
5146
  font-size: 10px;
@@ -3829,14 +5151,14 @@ var Badge = styled3.span`
3829
5151
  color: ${({ theme }) => theme.colors.neutral0};
3830
5152
  background: ${({ theme }) => theme.colors.neutral800};
3831
5153
  `;
3832
- var CardBox = styled3.div`
5154
+ var CardBox = styled4.div`
3833
5155
  position: relative;
3834
5156
  &:hover .bs-quick,
3835
5157
  &:focus-within .bs-quick {
3836
5158
  opacity: 1;
3837
5159
  }
3838
5160
  `;
3839
- var CardBadges = styled3.div`
5161
+ var CardBadges = styled4.div`
3840
5162
  position: absolute;
3841
5163
  top: 14px;
3842
5164
  left: 14px;
@@ -3846,7 +5168,7 @@ var CardBadges = styled3.div`
3846
5168
  gap: 4px;
3847
5169
  pointer-events: none;
3848
5170
  `;
3849
- var Round = styled3.button`
5171
+ var Round = styled4.button`
3850
5172
  position: absolute;
3851
5173
  right: 14px;
3852
5174
  display: inline-flex;
@@ -3869,7 +5191,7 @@ var Round = styled3.button`
3869
5191
  transition: opacity 120ms;
3870
5192
  }
3871
5193
  `;
3872
- var Mono = styled3.code`
5194
+ var Mono = styled4.code`
3873
5195
  font-size: 12px;
3874
5196
  color: ${({ theme }) => theme.colors.neutral600};
3875
5197
  `;
@@ -3885,9 +5207,9 @@ var TYPE_ICONS = { hero: "hero", text: "text", media: "image", listing: "list",
3885
5207
  var FILTER_MENUS = ["tags", "media", "content"];
3886
5208
  var toggled = (list, value) => list.includes(value) ? list.filter((item) => item !== value) : [...list, value];
3887
5209
  function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3888
- const [open, setOpen] = React4.useState(false);
3889
- const ref = React4.useRef(null);
3890
- React4.useEffect(() => {
5210
+ const [open, setOpen] = React5.useState(false);
5211
+ const ref = React5.useRef(null);
5212
+ React5.useEffect(() => {
3891
5213
  if (!open) return;
3892
5214
  const down = (event) => {
3893
5215
  if (!ref.current?.contains(event.target)) setOpen(false);
@@ -3905,8 +5227,8 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3905
5227
  window.removeEventListener("keydown", key, true);
3906
5228
  };
3907
5229
  }, [open]);
3908
- return /* @__PURE__ */ jsxs3(Menu, { ref, "data-testid": `gallery-filter-${name}`, children: [
3909
- /* @__PURE__ */ jsxs3(
5230
+ return /* @__PURE__ */ jsxs4(Menu, { ref, "data-testid": `gallery-filter-${name}`, children: [
5231
+ /* @__PURE__ */ jsxs4(
3910
5232
  MenuButton,
3911
5233
  {
3912
5234
  type: "button",
@@ -3915,12 +5237,12 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3915
5237
  onClick: () => setOpen(!open),
3916
5238
  children: [
3917
5239
  picked.length ? `${label} (${picked.length})` : label,
3918
- /* @__PURE__ */ jsx5(Icon, { name: "chevron", size: 14 })
5240
+ /* @__PURE__ */ jsx6(Icon, { name: "chevron", size: 14 })
3919
5241
  ]
3920
5242
  }
3921
5243
  ),
3922
- open && /* @__PURE__ */ jsx5(Popover, { role: "group", "aria-label": label, children: options.map(([value, count]) => /* @__PURE__ */ jsxs3("label", { children: [
3923
- /* @__PURE__ */ jsx5(
5244
+ open && /* @__PURE__ */ jsx6(Popover, { role: "group", "aria-label": label, children: options.map(([value, count]) => /* @__PURE__ */ jsxs4("label", { children: [
5245
+ /* @__PURE__ */ jsx6(
3924
5246
  "input",
3925
5247
  {
3926
5248
  type: "checkbox",
@@ -3929,23 +5251,23 @@ function FilterMenu({ name, label, options, picked, onChange, labelOf }) {
3929
5251
  "data-testid": `gallery-option-${name}-${value}`
3930
5252
  }
3931
5253
  ),
3932
- /* @__PURE__ */ jsx5("span", { children: labelOf(value) }),
3933
- /* @__PURE__ */ jsx5("span", { className: "bs-count", children: count })
5254
+ /* @__PURE__ */ jsx6("span", { children: labelOf(value) }),
5255
+ /* @__PURE__ */ jsx6("span", { className: "bs-count", children: count })
3934
5256
  ] }, value)) })
3935
5257
  ] });
3936
5258
  }
3937
5259
  function Badges({ entry, t, tags }) {
3938
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
3939
- entry.facets.map((facet) => /* @__PURE__ */ jsx5(Badge, { children: t.facets[facet] || facet }, facet)),
3940
- tags && entry.tags.map((tag) => /* @__PURE__ */ jsx5(Badge, { children: tag }, `tag:${tag}`))
5260
+ return /* @__PURE__ */ jsxs4(Fragment5, { children: [
5261
+ entry.facets.map((facet) => /* @__PURE__ */ jsx6(Badge, { children: t.facets[facet] || facet }, facet)),
5262
+ tags && entry.tags.map((tag) => /* @__PURE__ */ jsx6(Badge, { children: tag }, `tag:${tag}`))
3941
5263
  ] });
3942
5264
  }
3943
5265
  function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, onStar }) {
3944
5266
  const t = useMessages();
3945
- const timer = React4.useRef(null);
3946
- React4.useEffect(() => () => clearTimeout(timer.current), []);
3947
- return /* @__PURE__ */ jsxs3(CardBox, { title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
3948
- /* @__PURE__ */ jsxs3(
5267
+ const timer = React5.useRef(null);
5268
+ React5.useEffect(() => () => clearTimeout(timer.current), []);
5269
+ return /* @__PURE__ */ jsxs4(CardBox, { title: entry.uid, "data-testid": `blockscene-${entry.uid}`, children: [
5270
+ /* @__PURE__ */ jsxs4(
3949
5271
  Tile,
3950
5272
  {
3951
5273
  type: "button",
@@ -3962,7 +5284,7 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3962
5284
  onInsert();
3963
5285
  },
3964
5286
  children: [
3965
- /* @__PURE__ */ jsx5(
5287
+ /* @__PURE__ */ jsx6(
3966
5288
  Thumb,
3967
5289
  {
3968
5290
  candidates: entry.candidates,
@@ -3971,9 +5293,9 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3971
5293
  noPreview: t.noPreview
3972
5294
  }
3973
5295
  ),
3974
- /* @__PURE__ */ jsx5(Typography2, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
3975
- entry.description && /* @__PURE__ */ jsx5(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
3976
- showFields && entry.fields.length > 0 && /* @__PURE__ */ jsx5(
5296
+ /* @__PURE__ */ jsx6(Typography2, { variant: "pi", fontWeight: "bold", textColor: "neutral800", ellipsis: true, children: entry.label }),
5297
+ entry.description && /* @__PURE__ */ jsx6(Clamp, { variant: "pi", textColor: "neutral600", children: entry.description }),
5298
+ showFields && entry.fields.length > 0 && /* @__PURE__ */ jsx6(
3977
5299
  Typography2,
3978
5300
  {
3979
5301
  variant: "pi",
@@ -3986,8 +5308,8 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3986
5308
  ]
3987
5309
  }
3988
5310
  ),
3989
- /* @__PURE__ */ jsx5(CardBadges, { children: /* @__PURE__ */ jsx5(Badges, { entry, t }) }),
3990
- /* @__PURE__ */ jsx5(
5311
+ /* @__PURE__ */ jsx6(CardBadges, { children: /* @__PURE__ */ jsx6(Badges, { entry, t }) }),
5312
+ /* @__PURE__ */ jsx6(
3991
5313
  Round,
3992
5314
  {
3993
5315
  type: "button",
@@ -3998,10 +5320,10 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
3998
5320
  title: starred ? t.unstar : t.star,
3999
5321
  onClick: onStar,
4000
5322
  "data-testid": `gallery-star-${entry.uid}`,
4001
- children: /* @__PURE__ */ jsx5(Icon, { name: "star", size: 16, filled: starred })
5323
+ children: /* @__PURE__ */ jsx6(Icon, { name: "star", size: 16, filled: starred })
4002
5324
  }
4003
5325
  ),
4004
- /* @__PURE__ */ jsx5(
5326
+ /* @__PURE__ */ jsx6(
4005
5327
  Round,
4006
5328
  {
4007
5329
  type: "button",
@@ -4012,19 +5334,19 @@ function Card({ entry, palette, showFields, starred, active, onOpen, onInsert, o
4012
5334
  title: t.f("quickInsert", { label: entry.label }),
4013
5335
  onClick: onInsert,
4014
5336
  "data-testid": `gallery-quick-${entry.uid}`,
4015
- children: /* @__PURE__ */ jsx5(Icon, { name: "plus", size: 16 })
5337
+ children: /* @__PURE__ */ jsx6(Icon, { name: "plus", size: 16 })
4016
5338
  }
4017
5339
  )
4018
5340
  ] });
4019
5341
  }
4020
- var Scrim = styled3.div`
5342
+ var Scrim = styled4.div`
4021
5343
  position: absolute;
4022
5344
  inset: 0;
4023
5345
  z-index: 4;
4024
5346
  opacity: 0.35;
4025
5347
  background: ${({ theme }) => theme.colors.neutral800};
4026
5348
  `;
4027
- var Panel = styled3.section`
5349
+ var Panel = styled4.section`
4028
5350
  position: absolute;
4029
5351
  inset: 16px;
4030
5352
  z-index: 5;
@@ -4037,7 +5359,7 @@ var Panel = styled3.section`
4037
5359
  box-shadow: ${({ theme }) => theme.shadows?.popupShadow || "0 8px 32px rgba(33, 33, 52, 0.3)"};
4038
5360
  transform-origin: top left;
4039
5361
  `;
4040
- var Stage = styled3.div`
5362
+ var Stage = styled4.div`
4041
5363
  position: relative;
4042
5364
  flex: 1;
4043
5365
  min-height: 0;
@@ -4046,7 +5368,7 @@ var Stage = styled3.div`
4046
5368
  background-image: ${({ theme }) => stageBackground(theme).backgroundImage};
4047
5369
  background-size: 24px 24px;
4048
5370
  `;
4049
- var Still = styled3.div`
5371
+ var Still = styled4.div`
4050
5372
  position: absolute;
4051
5373
  inset: 0;
4052
5374
  /* Hidden once the live page has faded in over it (device widths would show it in the gutters). */
@@ -4065,7 +5387,7 @@ var Still = styled3.div`
4065
5387
  object-fit: contain;
4066
5388
  }
4067
5389
  `;
4068
- var Live = styled3.iframe`
5390
+ var Live = styled4.iframe`
4069
5391
  position: absolute;
4070
5392
  top: 0;
4071
5393
  border: 0;
@@ -4077,14 +5399,14 @@ var Live = styled3.iframe`
4077
5399
  transition: none;
4078
5400
  }
4079
5401
  `;
4080
- var Strip = styled3.div`
5402
+ var Strip = styled4.div`
4081
5403
  display: flex;
4082
5404
  flex-direction: column;
4083
5405
  gap: 6px;
4084
5406
  padding: 10px 12px;
4085
5407
  border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
4086
5408
  `;
4087
- var FieldsButton = styled3.button`
5409
+ var FieldsButton = styled4.button`
4088
5410
  border: 0;
4089
5411
  padding: 0;
4090
5412
  cursor: pointer;
@@ -4115,9 +5437,9 @@ var flip = (panel, scrim, card, back) => {
4115
5437
  var newChannel = () => crypto.randomUUID?.() || `${Date.now()}-${Math.random().toString(36).slice(2)}`;
4116
5438
  function useLiveSource(entry, config, components, get, contentType, locale) {
4117
5439
  const editor = config?.editor || {};
4118
- const [native, setNative] = React4.useState(null);
5440
+ const [native, setNative] = React5.useState(null);
4119
5441
  const plain = editor.blockPreviewUrl ? blockPreviewSrc(editor.blockPreviewUrl, entry.uid, { locale: locale || "" }) : null;
4120
- React4.useEffect(() => {
5442
+ React5.useEffect(() => {
4121
5443
  if (editor.blockPreviewUrl || editor.previewUrl || !contentType || !get) return;
4122
5444
  let active = true;
4123
5445
  get(`/content-manager/preview/url/${contentType}?${new URLSearchParams({ status: "draft", ...locale ? { locale } : {} })}`).then(({ data }) => {
@@ -4128,7 +5450,7 @@ function useLiveSource(entry, config, components, get, contentType, locale) {
4128
5450
  active = false;
4129
5451
  };
4130
5452
  }, [editor.blockPreviewUrl, editor.previewUrl, contentType, locale, get]);
4131
- const channel = React4.useMemo(newChannel, []);
5453
+ const channel = React5.useMemo(newChannel, []);
4132
5454
  if (editor.blockPreviewUrl) return plain ? { kind: "plain", src: plain, origin: "", channel } : null;
4133
5455
  const base = editor.previewUrl || native;
4134
5456
  if (!base) return null;
@@ -4143,18 +5465,18 @@ function useLiveSource(entry, config, components, get, contentType, locale) {
4143
5465
  var LIVE_TIMEOUT = 8e3;
4144
5466
  function Magnify({ entry, palette, config, components, get, contentType, locale, starred, onStar, onInsert, onClose, cardOf }) {
4145
5467
  const t = useMessages();
4146
- const panel = React4.useRef(null);
4147
- const scrim = React4.useRef(null);
4148
- const closeButton = React4.useRef(null);
4149
- const frame2 = React4.useRef(null);
4150
- const closing = React4.useRef(false);
4151
- const [stageEl, setStageEl] = React4.useState(null);
5468
+ const panel = React5.useRef(null);
5469
+ const scrim = React5.useRef(null);
5470
+ const closeButton = React5.useRef(null);
5471
+ const frame2 = React5.useRef(null);
5472
+ const closing = React5.useRef(false);
5473
+ const [stageEl, setStageEl] = React5.useState(null);
4152
5474
  const stage = useStageSize(stageEl);
4153
- const [device, setDevice] = React4.useState("fit");
4154
- const [fields, setFields] = React4.useState(false);
4155
- const [state, setState] = React4.useState("loading");
5475
+ const [device, setDevice] = React5.useState("fit");
5476
+ const [fields, setFields] = React5.useState(false);
5477
+ const [state, setState] = React5.useState("loading");
4156
5478
  const live = useLiveSource(entry, config, components, get, contentType, locale);
4157
- React4.useLayoutEffect(() => {
5479
+ React5.useLayoutEffect(() => {
4158
5480
  flip(panel.current, scrim.current, cardOf(entry.uid), false);
4159
5481
  closeButton.current?.querySelector("button")?.focus({ preventScroll: true });
4160
5482
  }, []);
@@ -4170,9 +5492,9 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4170
5492
  if (animation) animation.onfinish = done;
4171
5493
  else done();
4172
5494
  };
4173
- const closeRef = React4.useRef(close);
5495
+ const closeRef = React5.useRef(close);
4174
5496
  closeRef.current = close;
4175
- React4.useEffect(() => {
5497
+ React5.useEffect(() => {
4176
5498
  const key = (event) => {
4177
5499
  if (event.key !== "Escape") return;
4178
5500
  event.stopPropagation();
@@ -4183,7 +5505,7 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4183
5505
  return () => window.removeEventListener("keydown", key, true);
4184
5506
  }, []);
4185
5507
  const src = live?.src;
4186
- React4.useEffect(() => {
5508
+ React5.useEffect(() => {
4187
5509
  if (!live) return;
4188
5510
  setState("loading");
4189
5511
  const timer = setTimeout(() => setState((s) => s === "ready" ? s : "failed"), LIVE_TIMEOUT);
@@ -4212,11 +5534,11 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4212
5534
  if (live?.kind === "plain") setState("ready");
4213
5535
  else frame2.current?.contentWindow?.postMessage({ protocol: PROTOCOL, channel: live.channel, type: "ping" }, live.origin);
4214
5536
  };
4215
- return /* @__PURE__ */ jsxs3(Fragment3, { children: [
4216
- /* @__PURE__ */ jsx5(Scrim, { ref: scrim, onClick: close, "data-testid": "gallery-magnify-scrim" }),
4217
- /* @__PURE__ */ jsxs3(Panel, { ref: panel, "aria-label": entry.label, "data-testid": "gallery-detail", "data-live": live ? state : "none", children: [
4218
- /* @__PURE__ */ jsxs3(Flex2, { gap: 2, padding: 2, alignItems: "center", justifyContent: "space-between", children: [
4219
- /* @__PURE__ */ jsx5(Flex2, { gap: 1, role: "group", "aria-label": t.deviceGroup, "data-testid": "gallery-magnify-devices", children: Object.keys(DEVICES).map((value) => /* @__PURE__ */ jsx5(
5537
+ return /* @__PURE__ */ jsxs4(Fragment5, { children: [
5538
+ /* @__PURE__ */ jsx6(Scrim, { ref: scrim, onClick: close, "data-testid": "gallery-magnify-scrim" }),
5539
+ /* @__PURE__ */ jsxs4(Panel, { ref: panel, "aria-label": entry.label, "data-testid": "gallery-detail", "data-live": live ? state : "none", children: [
5540
+ /* @__PURE__ */ jsxs4(Flex2, { gap: 2, padding: 2, alignItems: "center", justifyContent: "space-between", children: [
5541
+ /* @__PURE__ */ jsx6(Flex2, { gap: 1, role: "group", "aria-label": t.deviceGroup, "data-testid": "gallery-magnify-devices", children: Object.keys(DEVICES).map((value) => /* @__PURE__ */ jsx6(
4220
5542
  Tool,
4221
5543
  {
4222
5544
  icon: value,
@@ -4226,12 +5548,12 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4226
5548
  },
4227
5549
  value
4228
5550
  )) }),
4229
- live && state === "failed" && /* @__PURE__ */ jsx5(Typography2, { variant: "pi", textColor: "neutral600", "data-testid": "gallery-magnify-note", children: t.livePreviewFailed }),
4230
- /* @__PURE__ */ jsx5("div", { ref: closeButton, children: /* @__PURE__ */ jsx5(Tool, { icon: "close", label: t.closeDetail, onClick: close }) })
5551
+ live && state === "failed" && /* @__PURE__ */ jsx6(Typography2, { variant: "pi", textColor: "neutral600", "data-testid": "gallery-magnify-note", children: t.livePreviewFailed }),
5552
+ /* @__PURE__ */ jsx6("div", { ref: closeButton, children: /* @__PURE__ */ jsx6(Tool, { icon: "close", label: t.closeDetail, onClick: close }) })
4231
5553
  ] }),
4232
- /* @__PURE__ */ jsxs3(Stage, { ref: setStageEl, $device: device !== "fit", "data-device": device, children: [
4233
- /* @__PURE__ */ jsx5(Still, { $covered: Boolean(live) && state === "ready", children: /* @__PURE__ */ jsx5(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview, eager: true }) }),
4234
- live && /* @__PURE__ */ jsx5(
5554
+ /* @__PURE__ */ jsxs4(Stage, { ref: setStageEl, $device: device !== "fit", "data-device": device, children: [
5555
+ /* @__PURE__ */ jsx6(Still, { $covered: Boolean(live) && state === "ready", children: /* @__PURE__ */ jsx6(Thumb, { candidates: entry.candidates, template: entry.template, palette, noPreview: t.noPreview, eager: true }) }),
5556
+ live && /* @__PURE__ */ jsx6(
4235
5557
  Live,
4236
5558
  {
4237
5559
  ref: frame2,
@@ -4247,23 +5569,23 @@ function Magnify({ entry, palette, config, components, get, contentType, locale,
4247
5569
  live.src
4248
5570
  )
4249
5571
  ] }),
4250
- /* @__PURE__ */ jsxs3(Strip, { children: [
4251
- /* @__PURE__ */ jsxs3(Flex2, { gap: 2, alignItems: "center", wrap: "wrap", children: [
4252
- /* @__PURE__ */ jsx5(Typography2, { variant: "omega", fontWeight: "bold", tag: "h3", ellipsis: true, children: entry.label }),
4253
- /* @__PURE__ */ jsx5(Mono, { children: entry.uid }),
4254
- /* @__PURE__ */ jsx5(Badge, { children: t.typologies[entry.typology] || entry.typology }),
4255
- /* @__PURE__ */ jsx5(Badges, { entry, t, tags: true }),
4256
- /* @__PURE__ */ jsxs3(Flex2, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
4257
- entry.fields.length > 0 && /* @__PURE__ */ jsx5(FieldsButton, { type: "button", "aria-expanded": fields, onClick: () => setFields(!fields), "data-testid": "gallery-detail-fields-toggle", children: `${t.showFields} (${entry.fields.length})` }),
4258
- /* @__PURE__ */ jsx5(Tool, { icon: "star", label: starred ? t.unstar : t.star, active: starred, onClick: onStar, "data-testid": "gallery-detail-star" }),
4259
- /* @__PURE__ */ jsx5(Button2, { onClick: onInsert, "data-testid": "gallery-insert", children: t.insert })
5572
+ /* @__PURE__ */ jsxs4(Strip, { children: [
5573
+ /* @__PURE__ */ jsxs4(Flex2, { gap: 2, alignItems: "center", wrap: "wrap", children: [
5574
+ /* @__PURE__ */ jsx6(Typography2, { variant: "omega", fontWeight: "bold", tag: "h3", ellipsis: true, children: entry.label }),
5575
+ /* @__PURE__ */ jsx6(Mono, { children: entry.uid }),
5576
+ /* @__PURE__ */ jsx6(Badge, { children: t.typologies[entry.typology] || entry.typology }),
5577
+ /* @__PURE__ */ jsx6(Badges, { entry, t, tags: true }),
5578
+ /* @__PURE__ */ jsxs4(Flex2, { gap: 2, alignItems: "center", style: { marginLeft: "auto" }, children: [
5579
+ entry.fields.length > 0 && /* @__PURE__ */ jsx6(FieldsButton, { type: "button", "aria-expanded": fields, onClick: () => setFields(!fields), "data-testid": "gallery-detail-fields-toggle", children: `${t.showFields} (${entry.fields.length})` }),
5580
+ /* @__PURE__ */ jsx6(Tool, { icon: "star", label: starred ? t.unstar : t.star, active: starred, onClick: onStar, "data-testid": "gallery-detail-star" }),
5581
+ /* @__PURE__ */ jsx6(Button2, { onClick: onInsert, "data-testid": "gallery-insert", children: t.insert })
4260
5582
  ] })
4261
5583
  ] }),
4262
- entry.description && /* @__PURE__ */ jsx5(Clamp, { variant: "pi", textColor: "neutral700", children: entry.description }),
4263
- fields && /* @__PURE__ */ jsx5(Flex2, { gap: 3, wrap: "wrap", "data-testid": "gallery-detail-fields", children: entry.fields.map((field) => /* @__PURE__ */ jsxs3(Typography2, { variant: "pi", textColor: "neutral800", children: [
4264
- /* @__PURE__ */ jsx5("span", { children: field.name }),
5584
+ entry.description && /* @__PURE__ */ jsx6(Clamp, { variant: "pi", textColor: "neutral700", children: entry.description }),
5585
+ fields && /* @__PURE__ */ jsx6(Flex2, { gap: 3, wrap: "wrap", "data-testid": "gallery-detail-fields", children: entry.fields.map((field) => /* @__PURE__ */ jsxs4(Typography2, { variant: "pi", textColor: "neutral800", children: [
5586
+ /* @__PURE__ */ jsx6("span", { children: field.name }),
4265
5587
  " ",
4266
- /* @__PURE__ */ jsx5(Mono, { children: field.type })
5588
+ /* @__PURE__ */ jsx6(Mono, { children: field.type })
4267
5589
  ] }, field.name)) })
4268
5590
  ] })
4269
5591
  ] })
@@ -4283,22 +5605,22 @@ function ZoneGallery({
4283
5605
  locale
4284
5606
  }) {
4285
5607
  const t = useMessages();
4286
- const grid = React4.useRef(null);
5608
+ const grid = React5.useRef(null);
4287
5609
  const cardOf = (uid) => grid.current?.querySelector(`[data-testid="blockscene-${CSS.escape(uid)}"]`) || null;
4288
- const [ownOpen, setOwnOpen] = React4.useState(false);
5610
+ const [ownOpen, setOwnOpen] = React5.useState(false);
4289
5611
  const open = controlled ? controlled.open : ownOpen;
4290
5612
  const setOpen = controlled ? controlled.onOpenChange : setOwnOpen;
4291
- const [query, setQuery] = React4.useState("");
4292
- const [view, setView] = React4.useState("all");
4293
- const [picked, setPicked] = React4.useState(NO_FILTERS);
4294
- const [detail, setDetail] = React4.useState(null);
4295
- const [collapsed, setCollapsed] = React4.useState(readCollapsed);
4296
- const [prefs, setPrefs] = React4.useState({ starred: [], recent: [] });
4297
- const [showFields, setShowFields] = React4.useState(readShowFields);
4298
- const [columns, setColumns] = React4.useState(readColumns);
4299
- const [config, setConfig] = React4.useState(null);
4300
- const [error, setError] = React4.useState("");
4301
- React4.useEffect(() => {
5613
+ const [query, setQuery] = React5.useState("");
5614
+ const [view, setView] = React5.useState("all");
5615
+ const [picked, setPicked] = React5.useState(NO_FILTERS);
5616
+ const [detail, setDetail] = React5.useState(null);
5617
+ const [collapsed, setCollapsed] = React5.useState(readCollapsed);
5618
+ const [prefs, setPrefs] = React5.useState({ starred: [], recent: [] });
5619
+ const [showFields, setShowFields] = React5.useState(readShowFields);
5620
+ const [columns, setColumns] = React5.useState(readColumns);
5621
+ const [config, setConfig] = React5.useState(null);
5622
+ const [error, setError] = React5.useState("");
5623
+ React5.useEffect(() => {
4302
5624
  if (controlled) return;
4303
5625
  const onClick = (event) => {
4304
5626
  const button = event.target?.closest?.("button");
@@ -4310,7 +5632,7 @@ function ZoneGallery({
4310
5632
  document.addEventListener("click", onClick, true);
4311
5633
  return () => document.removeEventListener("click", onClick, true);
4312
5634
  }, [controlled, zone.name, zone.label]);
4313
- React4.useEffect(() => {
5635
+ React5.useEffect(() => {
4314
5636
  if (!open) return;
4315
5637
  let active = true;
4316
5638
  setError("");
@@ -4377,7 +5699,7 @@ function ZoneGallery({
4377
5699
  setCollapsed(!collapsed);
4378
5700
  remember(SIDEBAR_KEY, collapsed ? "expanded" : "collapsed");
4379
5701
  };
4380
- const nav = (key, icon, label, count) => /* @__PURE__ */ jsxs3(
5702
+ const nav = (key, icon, label, count) => /* @__PURE__ */ jsxs4(
4381
5703
  NavItem,
4382
5704
  {
4383
5705
  type: "button",
@@ -4389,34 +5711,25 @@ function ZoneGallery({
4389
5711
  onClick: () => setView(key),
4390
5712
  "data-testid": `gallery-nav-${key}`,
4391
5713
  children: [
4392
- /* @__PURE__ */ jsx5(Icon, { name: icon }),
4393
- !collapsed && /* @__PURE__ */ jsxs3(Fragment3, { children: [
4394
- /* @__PURE__ */ jsx5("span", { className: "bs-label", children: label }),
4395
- /* @__PURE__ */ jsx5("span", { className: "bs-count", children: count })
5714
+ /* @__PURE__ */ jsx6(Icon, { name: icon }),
5715
+ !collapsed && /* @__PURE__ */ jsxs4(Fragment5, { children: [
5716
+ /* @__PURE__ */ jsx6("span", { className: "bs-label", children: label }),
5717
+ /* @__PURE__ */ jsx6("span", { className: "bs-count", children: count })
4396
5718
  ] })
4397
5719
  ]
4398
5720
  },
4399
5721
  key
4400
5722
  );
4401
- return /* @__PURE__ */ jsx5(
5723
+ return /* @__PURE__ */ jsx6(
4402
5724
  Modal2,
4403
5725
  {
4404
5726
  open,
4405
5727
  onOpenChange: setOpen,
4406
5728
  title: t.gallery,
4407
- trigger: controlled ? null : /* @__PURE__ */ jsx5(
4408
- Button2,
4409
- {
4410
- variant: "secondary",
4411
- fullWidth: true,
4412
- onClick: () => setOpen(true),
4413
- "data-testid": `open-gallery-${zone.name}`,
4414
- children: t.add
4415
- }
4416
- ),
4417
- children: /* @__PURE__ */ jsxs3(Layout, { children: [
4418
- /* @__PURE__ */ jsxs3(Side, { $collapsed: collapsed, "aria-label": t.gallery, "data-testid": `gallery-sidebar-${zone.name}`, "data-collapsed": collapsed, children: [
4419
- /* @__PURE__ */ jsx5(Flex2, { justifyContent: collapsed ? "center" : "flex-end", paddingBottom: 2, children: /* @__PURE__ */ jsx5(
5729
+ trigger: null,
5730
+ children: /* @__PURE__ */ jsxs4(Layout, { children: [
5731
+ /* @__PURE__ */ jsxs4(Side, { $collapsed: collapsed, "aria-label": t.gallery, "data-testid": `gallery-sidebar-${zone.name}`, "data-collapsed": collapsed, children: [
5732
+ /* @__PURE__ */ jsx6(Flex2, { justifyContent: collapsed ? "center" : "flex-end", paddingBottom: 2, children: /* @__PURE__ */ jsx6(
4420
5733
  Tool,
4421
5734
  {
4422
5735
  icon: "sidebar",
@@ -4425,19 +5738,19 @@ function ZoneGallery({
4425
5738
  "data-testid": "gallery-sidebar-toggle"
4426
5739
  }
4427
5740
  ) }),
4428
- options && /* @__PURE__ */ jsxs3(Fragment3, { children: [
5741
+ options && /* @__PURE__ */ jsxs4(Fragment5, { children: [
4429
5742
  nav("all", "grid", t.nav.all, options.total),
4430
5743
  nav("recent", "clock", t.nav.recent, inZone(prefs.recent).length),
4431
5744
  nav("starred", "star", t.nav.starred, inZone(prefs.starred).length),
4432
- !collapsed && /* @__PURE__ */ jsx5(Box, { paddingTop: 4, paddingBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ jsx5(Typography2, { variant: "sigma", textColor: "neutral600", children: t.typologiesTitle }) }),
5745
+ !collapsed && /* @__PURE__ */ jsx6(Box, { paddingTop: 4, paddingBottom: 1, paddingLeft: 2, children: /* @__PURE__ */ jsx6(Typography2, { variant: "sigma", textColor: "neutral600", children: t.typologiesTitle }) }),
4433
5746
  options.typologies.map(
4434
5747
  ([name, count]) => nav(name, TYPE_ICONS[name] || "text", t.typologies[name] || name, count)
4435
5748
  )
4436
5749
  ] })
4437
5750
  ] }),
4438
- /* @__PURE__ */ jsxs3(Main, { children: [
4439
- /* @__PURE__ */ jsxs3(Flex2, { gap: 3, alignItems: "center", wrap: "wrap", children: [
4440
- /* @__PURE__ */ jsx5(
5751
+ /* @__PURE__ */ jsxs4(Main, { children: [
5752
+ /* @__PURE__ */ jsxs4(Flex2, { gap: 3, alignItems: "center", wrap: "wrap", children: [
5753
+ /* @__PURE__ */ jsx6(
4441
5754
  Typography2,
4442
5755
  {
4443
5756
  variant: "omega",
@@ -4449,7 +5762,7 @@ function ZoneGallery({
4449
5762
  children: filtering ? t.f("countFiltered", { shown: entries.length, total: options?.total || 0 }) : t.f("countAll", { count: options?.total || 0 })
4450
5763
  }
4451
5764
  ),
4452
- /* @__PURE__ */ jsx5(Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ jsx5(
5765
+ /* @__PURE__ */ jsx6(Box, { style: { flex: 1, minWidth: "12rem" }, children: /* @__PURE__ */ jsx6(
4453
5766
  Searchbar,
4454
5767
  {
4455
5768
  name: `block-search-${zone.name}`,
@@ -4461,7 +5774,7 @@ function ZoneGallery({
4461
5774
  children: t.search
4462
5775
  }
4463
5776
  ) }),
4464
- options && FILTER_MENUS.filter((menu) => options[menu].length > 0).map((menu) => /* @__PURE__ */ jsx5(
5777
+ options && FILTER_MENUS.filter((menu) => options[menu].length > 0).map((menu) => /* @__PURE__ */ jsx6(
4465
5778
  FilterMenu,
4466
5779
  {
4467
5780
  name: menu,
@@ -4473,7 +5786,7 @@ function ZoneGallery({
4473
5786
  },
4474
5787
  menu
4475
5788
  )),
4476
- Toggle && /* @__PURE__ */ jsx5(
5789
+ Toggle && /* @__PURE__ */ jsx6(
4477
5790
  Toggle,
4478
5791
  {
4479
5792
  name: `block-fields-${zone.name}`,
@@ -4483,9 +5796,9 @@ function ZoneGallery({
4483
5796
  onChange: changeShowFields
4484
5797
  }
4485
5798
  ),
4486
- /* @__PURE__ */ jsxs3(Flex2, { gap: 2, alignItems: "center", children: [
4487
- /* @__PURE__ */ jsx5(Typography2, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
4488
- /* @__PURE__ */ jsx5(
5799
+ /* @__PURE__ */ jsxs4(Flex2, { gap: 2, alignItems: "center", children: [
5800
+ /* @__PURE__ */ jsx6(Typography2, { variant: "pi", textColor: "neutral600", id: `block-columns-${zone.name}`, children: t.columns }),
5801
+ /* @__PURE__ */ jsx6(
4489
5802
  Slider,
4490
5803
  {
4491
5804
  type: "range",
@@ -4498,11 +5811,11 @@ function ZoneGallery({
4498
5811
  onChange: (e) => changeColumns(Number(e.target.value))
4499
5812
  }
4500
5813
  ),
4501
- /* @__PURE__ */ jsx5(Typography2, { variant: "pi", fontWeight: "bold", children: columns })
5814
+ /* @__PURE__ */ jsx6(Typography2, { variant: "pi", fontWeight: "bold", children: columns })
4502
5815
  ] })
4503
5816
  ] }),
4504
- chips.length > 0 && /* @__PURE__ */ jsxs3(Flex2, { gap: 2, wrap: "wrap", "data-testid": "gallery-chips", children: [
4505
- chips.map(({ menu, value }) => /* @__PURE__ */ jsxs3(
5817
+ chips.length > 0 && /* @__PURE__ */ jsxs4(Flex2, { gap: 2, wrap: "wrap", "data-testid": "gallery-chips", children: [
5818
+ chips.map(({ menu, value }) => /* @__PURE__ */ jsxs4(
4506
5819
  Chip,
4507
5820
  {
4508
5821
  type: "button",
@@ -4510,16 +5823,16 @@ function ZoneGallery({
4510
5823
  onClick: () => setPicked({ ...picked, [menu]: picked[menu].filter((item) => item !== value) }),
4511
5824
  children: [
4512
5825
  labelOf(menu, value),
4513
- /* @__PURE__ */ jsx5(Icon, { name: "close", size: 12 })
5826
+ /* @__PURE__ */ jsx6(Icon, { name: "close", size: 12 })
4514
5827
  ]
4515
5828
  },
4516
5829
  `${menu}:${value}`
4517
5830
  )),
4518
- /* @__PURE__ */ jsx5(Button2, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
5831
+ /* @__PURE__ */ jsx6(Button2, { variant: "tertiary", size: "S", onClick: () => setPicked(NO_FILTERS), "data-testid": "gallery-clear-all", children: t.clearAll })
4519
5832
  ] }),
4520
- /* @__PURE__ */ jsx5(Typography2, { variant: "pi", textColor: "neutral600", children: t.example }),
4521
- error ? /* @__PURE__ */ jsx5(Typography2, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ jsx5(Typography2, { children: t.loading }) : entries.length ? /* @__PURE__ */ jsxs3("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
4522
- /* @__PURE__ */ jsx5(
5833
+ /* @__PURE__ */ jsx6(Typography2, { variant: "pi", textColor: "neutral600", children: t.example }),
5834
+ error ? /* @__PURE__ */ jsx6(Typography2, { role: "alert", textColor: "danger600", children: error }) : !config ? /* @__PURE__ */ jsx6(Typography2, { children: t.loading }) : entries.length ? /* @__PURE__ */ jsxs4("div", { ref: grid, style: { position: "relative", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
5835
+ /* @__PURE__ */ jsx6(
4523
5836
  Flex2,
4524
5837
  {
4525
5838
  direction: "column",
@@ -4527,9 +5840,9 @@ function ZoneGallery({
4527
5840
  gap: 4,
4528
5841
  style: { overflowY: "auto", flex: 1, minHeight: 0, padding: "4px" },
4529
5842
  children: (view === "recent" ? [{ typology: "recent", entries }] : groupEntries(entries)).map(
4530
- ({ typology, entries: items }) => /* @__PURE__ */ jsxs3(Flex2, { direction: "column", alignItems: "stretch", gap: 2, children: [
4531
- /* @__PURE__ */ jsx5(Typography2, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${typology}`, children: `${typology === "recent" ? t.nav.recent : t.typologies[typology] || typology} (${items.length})` }),
4532
- /* @__PURE__ */ jsx5(Columns, { $columns: columns, children: items.map((entry) => /* @__PURE__ */ jsx5("div", { children: /* @__PURE__ */ jsx5(
5843
+ ({ typology, entries: items2 }) => /* @__PURE__ */ jsxs4(Flex2, { direction: "column", alignItems: "stretch", gap: 2, children: [
5844
+ /* @__PURE__ */ jsx6(Typography2, { variant: "sigma", textColor: "neutral600", "data-testid": `block-group-${typology}`, children: `${typology === "recent" ? t.nav.recent : t.typologies[typology] || typology} (${items2.length})` }),
5845
+ /* @__PURE__ */ jsx6(Columns, { $columns: columns, children: items2.map((entry) => /* @__PURE__ */ jsx6("div", { children: /* @__PURE__ */ jsx6(
4533
5846
  Card,
4534
5847
  {
4535
5848
  entry,
@@ -4546,7 +5859,7 @@ function ZoneGallery({
4546
5859
  )
4547
5860
  }
4548
5861
  ),
4549
- chosen && /* @__PURE__ */ jsx5(
5862
+ chosen && /* @__PURE__ */ jsx6(
4550
5863
  Magnify,
4551
5864
  {
4552
5865
  entry: chosen,
@@ -4564,9 +5877,9 @@ function ZoneGallery({
4564
5877
  },
4565
5878
  chosen.uid
4566
5879
  )
4567
- ] }) : /* @__PURE__ */ jsxs3(Flex2, { gap: 3, alignItems: "center", children: [
4568
- /* @__PURE__ */ jsx5(Typography2, { children: t.empty }),
4569
- filtering && /* @__PURE__ */ jsx5(Button2, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
5880
+ ] }) : /* @__PURE__ */ jsxs4(Flex2, { gap: 3, alignItems: "center", children: [
5881
+ /* @__PURE__ */ jsx6(Typography2, { children: t.empty }),
5882
+ filtering && /* @__PURE__ */ jsx6(Button2, { variant: "tertiary", size: "S", onClick: reset, children: t.clear })
4570
5883
  ] })
4571
5884
  ] })
4572
5885
  ] })
@@ -4588,12 +5901,12 @@ function useInitialAccordions({
4588
5901
  contentType,
4589
5902
  userId
4590
5903
  }) {
4591
- const applied = React4.useRef("");
4592
- const user = React4.useRef(userId);
5904
+ const applied = React5.useRef("");
5905
+ const user = React5.useRef(userId);
4593
5906
  user.current = userId;
4594
- const latest = React4.useRef(zones);
5907
+ const latest = React5.useRef(zones);
4595
5908
  latest.current = zones;
4596
- React4.useEffect(() => {
5909
+ React5.useEffect(() => {
4597
5910
  if (!editor?.enabled || !docKey || applied.current === docKey) return;
4598
5911
  if (applied.current.startsWith(`${contentType}:new`) && docKey.startsWith(`${contentType}:`)) {
4599
5912
  applied.current = docKey;
@@ -4640,24 +5953,31 @@ function useInitialAccordions({
4640
5953
  }, [docKey, editor?.enabled, editor?.initialState, contentType]);
4641
5954
  }
4642
5955
  var ZONE_ATTR = "data-blockscene-zone-controls";
4643
- function useLabelAnchor(zone, enabled) {
4644
- const [el, setEl] = React4.useState(null);
4645
- React4.useEffect(() => {
5956
+ function useZoneAnchor(zone, enabled) {
5957
+ const [el, setEl] = React5.useState(null);
5958
+ const filled = zone.count > 0;
5959
+ React5.useEffect(() => {
4646
5960
  if (!enabled) return;
4647
5961
  let frame2 = 0;
4648
5962
  const sync = () => {
4649
- const list = findZoneList(zone.label);
4650
- const row = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim());
5963
+ let host = null, after = null;
5964
+ if (filled) {
5965
+ const list = findZoneList(zone.label);
5966
+ host = list && [...list.parentElement?.children || []].find((child) => child !== list && child.textContent?.trim()) || null;
5967
+ } else {
5968
+ after = [...document.querySelectorAll("button")].find((button) => isNativeAddButton(button, zone)) || null;
5969
+ host = after?.parentElement || null;
5970
+ }
4651
5971
  let anchor = document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`);
4652
- if (anchor && anchor.parentElement !== row) {
5972
+ if (anchor && (anchor.parentElement !== host || after && anchor.previousElementSibling !== after)) {
4653
5973
  anchor.remove();
4654
5974
  anchor = null;
4655
5975
  }
4656
- if (!anchor && row) {
5976
+ if (!anchor && host) {
4657
5977
  anchor = document.createElement("span");
4658
5978
  anchor.setAttribute(ZONE_ATTR, zone.name);
4659
- anchor.style.cssText = "display:inline-flex;align-items:center;margin-left:8px";
4660
- row.appendChild(anchor);
5979
+ anchor.style.cssText = "display:inline-flex;align-items:center;margin-left:8px;white-space:nowrap";
5980
+ host.insertBefore(anchor, after ? after.nextSibling : null);
4661
5981
  }
4662
5982
  setEl(anchor);
4663
5983
  };
@@ -4675,14 +5995,42 @@ function useLabelAnchor(zone, enabled) {
4675
5995
  document.querySelector(`[${ZONE_ATTR}="${CSS.escape(zone.name)}"]`)?.remove();
4676
5996
  setEl(null);
4677
5997
  };
4678
- }, [zone.name, zone.label, enabled]);
5998
+ }, [zone.name, zone.label, enabled, filled]);
4679
5999
  return el;
4680
6000
  }
4681
- function ZoneControls({ zone, editor, contentType, userId, tools }) {
6001
+ function useRowStates(zone, enabled) {
6002
+ const [state, setState] = React5.useState({ closed: false, open: false });
6003
+ React5.useEffect(() => {
6004
+ if (!enabled) return;
6005
+ let frame2 = 0;
6006
+ const read = () => {
6007
+ frame2 = 0;
6008
+ const list = findZoneList(zone.label);
6009
+ const values = list ? shownToggles(list).map((button) => button.getAttribute("aria-expanded") === "true") : [];
6010
+ const closed = values.includes(false), open = values.includes(true);
6011
+ setState((prev) => prev.closed === closed && prev.open === open ? prev : { closed, open });
6012
+ };
6013
+ read();
6014
+ const observer = new MutationObserver(() => {
6015
+ if (!frame2) frame2 = requestAnimationFrame(read);
6016
+ });
6017
+ observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["aria-expanded", FOLDED] });
6018
+ return () => {
6019
+ observer.disconnect();
6020
+ cancelAnimationFrame(frame2);
6021
+ };
6022
+ }, [zone.label, enabled]);
6023
+ return state;
6024
+ }
6025
+ function ZoneControls({ zone, editor, contentType, userId, actions, extra, Menu: Menu3 }) {
4682
6026
  const t = useMessages();
4683
- const shown = Boolean(zone.count && (editor.showOpenAll || editor.showCloseAll || tools));
4684
- const anchor = useLabelAnchor(zone, shown);
4685
- if (!shown || !anchor) return null;
6027
+ const toggleShown = Boolean(zone.count && (editor.showOpenAll || editor.showCloseAll));
6028
+ const items2 = zoneMenuItems(zone, actions);
6029
+ const selecting = actions?.selection?.zone === zone.name;
6030
+ const anchor = useZoneAnchor(zone, toggleShown || Boolean(extra) || items2.length > 0 || selecting);
6031
+ const rows = useRowStates(zone, toggleShown && Boolean(anchor));
6032
+ if (!anchor) return null;
6033
+ const toggle = toggleShown && accordionToggle(rows.closed, rows.open, editor);
4686
6034
  const apply = (open) => {
4687
6035
  const list = findZoneList(zone.label);
4688
6036
  if (list) setAll(list, open, unstable_batchedUpdates);
@@ -4692,12 +6040,24 @@ function ZoneControls({ zone, editor, contentType, userId, tools }) {
4692
6040
  open ? "open" : "closed"
4693
6041
  );
4694
6042
  };
4695
- return createPortal3(
4696
- /* @__PURE__ */ jsxs3(Flex2, { gap: 1, "data-testid": `block-accordion-controls-${zone.name}`, children: [
4697
- editor.showOpenAll && /* @__PURE__ */ jsx5(Tool, { icon: "expand", label: t.openAll, onClick: () => apply(true) }),
4698
- editor.showCloseAll && /* @__PURE__ */ jsx5(Tool, { icon: "collapse", label: t.closeAll, onClick: () => apply(false) }),
4699
- tools
4700
- ] }),
6043
+ return createPortal4(
6044
+ /* @__PURE__ */ jsx6(Flex2, { gap: 2, alignItems: "center", wrap: "wrap", "data-testid": `block-accordion-controls-${zone.name}`, children: selecting ? /* @__PURE__ */ jsx6(SelectionBar, { zone, actions }) : /* @__PURE__ */ jsxs4(Fragment5, { children: [
6045
+ toggle && /* @__PURE__ */ jsx6(
6046
+ Button2,
6047
+ {
6048
+ size: "S",
6049
+ variant: "tertiary",
6050
+ startIcon: /* @__PURE__ */ jsx6(Icon, { name: toggle.action === "open" ? "expand" : "collapse", size: 14 }),
6051
+ "aria-expanded": !rows.closed,
6052
+ disabled: toggle.disabled,
6053
+ onClick: () => apply(toggle.action === "open"),
6054
+ "data-testid": `zone-toggle-${zone.name}`,
6055
+ children: toggle.action === "open" ? t.expandAll : t.collapseAll
6056
+ }
6057
+ ),
6058
+ extra,
6059
+ items2.length > 0 && /* @__PURE__ */ jsx6(Menu3, { label: t.moreActions, testid: `zone-more-${zone.name}`, items: items2 })
6060
+ ] }) }),
4701
6061
  anchor
4702
6062
  );
4703
6063
  }
@@ -4708,13 +6068,15 @@ function Gallery({
4708
6068
  contentType,
4709
6069
  userId,
4710
6070
  catalog,
6071
+ zoneTools = null,
6072
+ Menu: Menu3,
4711
6073
  ...props
4712
6074
  }) {
4713
6075
  useInitialAccordions({ zones, editor, docKey, contentType, userId });
4714
6076
  const actions = useRowActions({ zones, components: props.components, catalog, form: props.form });
4715
- React4.useEffect(() => stopAll, [docKey]);
4716
- return /* @__PURE__ */ jsxs3(Flex2, { direction: "column", alignItems: "stretch", gap: 3, children: [
4717
- editor.showRowThumbnails !== false && /* @__PURE__ */ jsx5(
6077
+ React5.useEffect(() => stopAll, [docKey]);
6078
+ return /* @__PURE__ */ jsxs4(Fragment5, { children: [
6079
+ editor.showRowThumbnails !== false && /* @__PURE__ */ jsx6(
4718
6080
  RowPreviews,
4719
6081
  {
4720
6082
  zones,
@@ -4723,19 +6085,29 @@ function Gallery({
4723
6085
  Modal: props.Modal
4724
6086
  }
4725
6087
  ),
4726
- /* @__PURE__ */ jsx5(RowActions, { zones, actions, Modal: props.Modal }),
4727
- zones.map((zone) => /* @__PURE__ */ jsxs3(Flex2, { direction: "column", alignItems: "stretch", gap: 2, children: [
4728
- zones.length > 1 && !zone.full && /* @__PURE__ */ jsx5(Typography2, { variant: "sigma", textColor: "neutral600", tag: "h3", children: zone.label }),
4729
- !zone.full && /* @__PURE__ */ jsx5(ZoneGallery, { zone, contentType, locale: String(docKey || "").split(":").pop(), ...props }),
4730
- zone.count === 0 && actions?.clip && /* @__PURE__ */ jsx5(Flex2, { children: /* @__PURE__ */ jsx5(ZoneRowTools, { zone, actions }) }),
4731
- /* @__PURE__ */ jsx5(
6088
+ /* @__PURE__ */ jsx6(RowActions, { zones, actions, Modal: props.Modal }),
6089
+ /* @__PURE__ */ jsx6(
6090
+ GroupRows,
6091
+ {
6092
+ zones,
6093
+ form: props.form,
6094
+ groups: catalog?.groups || null,
6095
+ docKey,
6096
+ labelOf: (row) => catalog?.components?.[row?.__component]?.label || props.components?.[row?.__component]?.info?.displayName || row?.__component || ""
6097
+ }
6098
+ ),
6099
+ zones.map((zone, index) => /* @__PURE__ */ jsxs4(React5.Fragment, { children: [
6100
+ !zone.full && /* @__PURE__ */ jsx6(ZoneGallery, { zone, contentType, locale: String(docKey || "").split(":").pop(), ...props }),
6101
+ /* @__PURE__ */ jsx6(
4732
6102
  ZoneControls,
4733
6103
  {
4734
6104
  zone,
4735
6105
  editor,
4736
6106
  contentType,
4737
6107
  userId,
4738
- tools: actions && actions.editor.clipboard !== false && /* @__PURE__ */ jsx5(ZoneRowTools, { zone, actions })
6108
+ actions,
6109
+ extra: index === 0 ? zoneTools : null,
6110
+ Menu: Menu3
4739
6111
  }
4740
6112
  )
4741
6113
  ] }, zone.name))
@@ -4743,24 +6115,24 @@ function Gallery({
4743
6115
  }
4744
6116
 
4745
6117
  // admin/Settings.tsx
4746
- import * as React5 from "react";
6118
+ import * as React6 from "react";
4747
6119
  import { Box as Box2, Button as Button3, Flex as Flex3, Searchbar as Searchbar2, Typography as Typography3 } from "@strapi/design-system";
4748
- import styled4 from "styled-components";
4749
- import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
6120
+ import styled5 from "styled-components";
6121
+ import { Fragment as Fragment6, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
4750
6122
  var COLOR2 = /^#[0-9A-Fa-f]{6}$/;
4751
- var Grid = styled4.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
4752
- var Card2 = styled4.div`
6123
+ var Grid = styled5.div` display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 16px; `;
6124
+ var Card2 = styled5.div`
4753
6125
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
4754
6126
  border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral0};
4755
6127
  `;
4756
- var Bar = styled4.div`
6128
+ var Bar = styled5.div`
4757
6129
  position: fixed; top: 0; z-index: 4; padding: 12px 32px;
4758
6130
  background: ${({ theme }) => theme.colors.neutral100}; border-bottom: 1px solid ${({ theme }) => theme.colors.neutral150};
4759
6131
  box-shadow: 0 1px 4px rgba(33, 33, 52, 0.1);
4760
6132
  `;
4761
6133
  function useMainRect(anchor) {
4762
- const [rect, setRect] = React5.useState({ left: 0, width: 0 });
4763
- React5.useEffect(() => {
6134
+ const [rect, setRect] = React6.useState({ left: 0, width: 0 });
6135
+ React6.useEffect(() => {
4764
6136
  const read = () => {
4765
6137
  let host = document.getElementById("main-content");
4766
6138
  for (let el = anchor.current?.parentElement; !host && el; el = el.parentElement) if (["auto", "scroll"].includes(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight) host = el;
@@ -4773,15 +6145,15 @@ function useMainRect(anchor) {
4773
6145
  });
4774
6146
  return rect;
4775
6147
  }
4776
- var Swatches = styled4.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
4777
- var Label = styled4.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
6148
+ var Swatches = styled5.div` display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; `;
6149
+ var Label = styled5.label` display: flex; flex-direction: column; gap: 4px; font-size: 12px; `;
4778
6150
  function ColorField({ name, label, value, onChange, disabled }) {
4779
6151
  const valid = COLOR2.test(value);
4780
- return /* @__PURE__ */ jsxs4(Label, { children: [
4781
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
4782
- /* @__PURE__ */ jsxs4(Flex3, { gap: 2, children: [
4783
- /* @__PURE__ */ jsx6("input", { type: "color", "aria-label": label, value: valid ? value : "#000000", disabled, onChange: (e) => onChange(e.target.value.toUpperCase()), style: { width: 40, height: 32, padding: 0, border: 0, background: "none" } }),
4784
- /* @__PURE__ */ jsx6(
6152
+ return /* @__PURE__ */ jsxs5(Label, { children: [
6153
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
6154
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 2, children: [
6155
+ /* @__PURE__ */ jsx7("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" } }),
6156
+ /* @__PURE__ */ jsx7(
4785
6157
  "input",
4786
6158
  {
4787
6159
  name,
@@ -4797,14 +6169,14 @@ function ColorField({ name, label, value, onChange, disabled }) {
4797
6169
  ] });
4798
6170
  }
4799
6171
  function TagsField({ name, label, hint, value, onChange, disabled }) {
4800
- const [text, setText] = React5.useState(value.join(", "));
4801
- return /* @__PURE__ */ jsxs4(Label, { children: [
4802
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
4803
- /* @__PURE__ */ jsx6("input", { name, value: text, disabled, onChange: (e) => {
6172
+ const [text, setText] = React6.useState(value.join(", "));
6173
+ return /* @__PURE__ */ jsxs5(Label, { children: [
6174
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
6175
+ /* @__PURE__ */ jsx7("input", { name, value: text, disabled, onChange: (e) => {
4804
6176
  setText(e.target.value);
4805
6177
  onChange([...new Set(e.target.value.split(",").map((tag) => tag.replace(/[<>]/g, "").trim().slice(0, 24)).filter(Boolean))].slice(0, 10));
4806
6178
  }, style: { padding: "6px 8px", border: "1px solid #dcdce4", borderRadius: 4, fontSize: 13 } }),
4807
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: hint })
6179
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: hint })
4808
6180
  ] });
4809
6181
  }
4810
6182
  var FIELD_UID = /^(plugin|global)::[\w.-]+$/;
@@ -4812,11 +6184,11 @@ var LAZY_MAX = 20;
4812
6184
  var parseUids = (text) => [...new Set(text.split(/[\s,]+/).filter(Boolean))];
4813
6185
  var badUids = (uids = []) => uids.length > LAZY_MAX || uids.some((uid) => !FIELD_UID.test(uid));
4814
6186
  function UidListField({ TextField: TextField2, value, onChange, ...props }) {
4815
- const [text, setText] = React5.useState(value.join(", "));
4816
- React5.useEffect(() => {
6187
+ const [text, setText] = React6.useState(value.join(", "));
6188
+ React6.useEffect(() => {
4817
6189
  if (parseUids(text).join() !== value.join()) setText(value.join(", "));
4818
6190
  }, [value.join()]);
4819
- return /* @__PURE__ */ jsx6(TextField2, { ...props, value: text, onChange: (v) => {
6191
+ return /* @__PURE__ */ jsx7(TextField2, { ...props, value: text, onChange: (v) => {
4820
6192
  setText(v);
4821
6193
  onChange(parseUids(v));
4822
6194
  } });
@@ -4826,73 +6198,148 @@ var SIDEBAR_MAX = 12;
4826
6198
  var ITEM_LABEL = /^[^<>]{1,40}$/;
4827
6199
  var badItem = (item) => !ITEM_LABEL.test(String(item.label || "").trim()) || !item.fields?.length;
4828
6200
  var SYSTEM_FIELDS2 = ["createdAt", "updatedAt", "publishedAt", "createdBy", "updatedBy", "locale", "localizations"];
4829
- var Item = styled4.div`
6201
+ var Item = styled5.div`
4830
6202
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 4px;
4831
6203
  border: 1px solid ${({ theme }) => theme.colors.neutral200}; background: ${({ theme }) => theme.colors.neutral100};
4832
6204
  `;
4833
- var Checks = styled4.fieldset`
6205
+ var Checks = styled5.fieldset`
4834
6206
  display: flex; flex-wrap: wrap; gap: 4px 16px; border: 0; padding: 0; margin: 0; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800};
4835
6207
  legend { font-size: 12px; font-weight: 600; margin-bottom: 4px; }
4836
6208
  label { display: inline-flex; align-items: center; gap: 6px; }
4837
6209
  `;
6210
+ var TOOLBAR = ["modes", "history", "devices", "status", "actions"];
6211
+ var DEVICE_NAMES = ["fit", "mobile", "tablet", "desktop"];
6212
+ var DEVICE_LABEL = /^[^<>]{1,24}$/;
6213
+ 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;
6214
+ var Row = styled5.div` display: flex; align-items: center; gap: 8px; min-height: 36px; font-size: 13px; color: ${({ theme }) => theme.colors.neutral800}; `;
6215
+ function PaneEditor({ id, toolbar, devices, set: set2, t, disabled, TextField: TextField2 }) {
6216
+ const move = (list, index, by) => {
6217
+ const next = [...list];
6218
+ [next[index], next[index + by]] = [next[index + by], next[index]];
6219
+ return next;
6220
+ };
6221
+ const arrows = (list, index, key) => /* @__PURE__ */ jsxs5(Fragment6, { children: [
6222
+ /* @__PURE__ */ jsx7(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index < 0 || index === 0, onClick: () => set2(key, move(list, index, -1)) }),
6223
+ /* @__PURE__ */ jsx7(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index < 0 || index === list.length - 1, onClick: () => set2(key, move(list, index, 1)) })
6224
+ ] });
6225
+ const check = (list, item, key) => /* @__PURE__ */ jsx7(
6226
+ "input",
6227
+ {
6228
+ type: "checkbox",
6229
+ name: `${id}-${key}-${item}`,
6230
+ checked: list.includes(item),
6231
+ disabled,
6232
+ onChange: (e) => set2(key, e.target.checked ? [...list, item] : list.filter((entry) => entry !== item))
6233
+ }
6234
+ );
6235
+ const width = (index, patch) => set2("previewDevices", devices.map((item, i) => i === index ? { ...item, ...patch } : item));
6236
+ return /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 3, "data-testid": `pane-editor-${id}`, children: [
6237
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.paneHelp }),
6238
+ /* @__PURE__ */ jsx7(Box2, { children: [...toolbar, ...TOOLBAR.filter((item) => !toolbar.includes(item))].map((item) => /* @__PURE__ */ jsxs5(Row, { "data-testid": `${id}-toolbar-${item}`, children: [
6239
+ arrows(toolbar, toolbar.indexOf(item), "previewToolbar"),
6240
+ /* @__PURE__ */ jsxs5("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
6241
+ check(toolbar, item, "previewToolbar"),
6242
+ t.toolbar[item]
6243
+ ] })
6244
+ ] }, item)) }),
6245
+ /* @__PURE__ */ jsx7(Typography3, { variant: "delta", tag: "h3", children: t.paneDevices }),
6246
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.paneDevicesHelp }),
6247
+ /* @__PURE__ */ jsx7(Box2, { children: [...devices, ...DEVICE_NAMES.filter((item) => !devices.includes(item))].map((item) => {
6248
+ const index = devices.indexOf(item);
6249
+ return /* @__PURE__ */ jsxs5(Row, { "data-testid": `${id}-device-${typeof item === "string" ? item : index}`, children: [
6250
+ arrows(devices, index, "previewDevices"),
6251
+ typeof item === "string" ? /* @__PURE__ */ jsxs5("label", { style: { display: "inline-flex", gap: 6, alignItems: "center" }, children: [
6252
+ check(devices, item, "previewDevices"),
6253
+ t.device[item]
6254
+ ] }) : /* @__PURE__ */ jsxs5(Fragment6, { children: [
6255
+ /* @__PURE__ */ jsx7(Box2, { style: { flex: "1 1 160px" }, children: /* @__PURE__ */ jsx7(TextField2, { name: `${id}-device-label-${index}`, label: t.paneWidthLabel, value: item.label, disabled, onChange: (v) => width(index, { label: v }) }) }),
6256
+ /* @__PURE__ */ jsx7(Box2, { style: { width: 140 }, children: /* @__PURE__ */ jsx7(
6257
+ TextField2,
6258
+ {
6259
+ name: `${id}-device-width-${index}`,
6260
+ label: t.paneWidth,
6261
+ value: Number.isFinite(item.width) ? String(item.width) : "",
6262
+ disabled,
6263
+ onChange: (v) => width(index, { width: /^\d{1,4}$/.test(v.trim()) ? Number(v.trim()) : NaN })
6264
+ }
6265
+ ) }),
6266
+ /* @__PURE__ */ jsx7(Tool, { icon: "close", label: t.paneRemoveWidth, disabled, onClick: () => set2("previewDevices", devices.filter((_, i) => i !== index)) })
6267
+ ] })
6268
+ ] }, typeof item === "string" ? item : `px-${index}`);
6269
+ }) }),
6270
+ /* @__PURE__ */ jsx7(Flex3, { children: /* @__PURE__ */ jsx7(
6271
+ Button3,
6272
+ {
6273
+ variant: "secondary",
6274
+ size: "S",
6275
+ disabled: disabled || devices.length >= 8,
6276
+ "data-testid": `${id}-add-width`,
6277
+ onClick: () => set2("previewDevices", [...devices, { label: "", width: 1280 }]),
6278
+ children: t.paneAddWidth
6279
+ }
6280
+ ) }),
6281
+ badDevices(devices) && /* @__PURE__ */ jsx7(Typography3, { role: "alert", variant: "pi", textColor: "danger600", children: t.paneInvalid })
6282
+ ] });
6283
+ }
4838
6284
  var DAYS = (n) => Number.isInteger(n) && n >= 1 && n <= 3650;
4839
- var badRetention = (h) => !h || !DAYS(h.retentionDays) || !DAYS(h.eventDays) || h.eventDays < h.retentionDays || !(Number.isInteger(h.maxSnapshots) && h.maxSnapshots >= 1 && h.maxSnapshots <= 1e3);
4840
- function HistorySettings({ types, history, set, t, disabled, ToggleField: ToggleField2, TextField: TextField2 }) {
6285
+ 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);
6286
+ function HistorySettings({ types, history, set: set2, t, disabled, ToggleField: ToggleField2, TextField: TextField2 }) {
4841
6287
  const all = history.contentTypes === "all";
4842
6288
  const list = all ? [] : history.contentTypes;
4843
- const number = (key) => /* @__PURE__ */ jsx6(Box2, { style: { minWidth: 200 }, children: /* @__PURE__ */ jsx6(
6289
+ const number = (key) => /* @__PURE__ */ jsx7(Box2, { style: { minWidth: 200 }, children: /* @__PURE__ */ jsx7(
4844
6290
  TextField2,
4845
6291
  {
4846
6292
  name: `history-${key}`,
4847
- label: t[{ retentionDays: "historyRetention", maxSnapshots: "historyMax", eventDays: "historyEventDays" }[key]],
6293
+ label: t[{ retentionDays: "historyRetention", maxSnapshots: "historyMax", eventDays: "historyEventDays", trashDays: "trashDays" }[key]],
4848
6294
  value: Number.isFinite(history[key]) ? String(history[key]) : "",
4849
6295
  disabled,
4850
- onChange: (v) => set(key, /^\d{1,5}$/.test(v.trim()) ? Number(v.trim()) : NaN)
6296
+ onChange: (v) => set2(key, /^\d{1,5}$/.test(v.trim()) ? Number(v.trim()) : NaN)
4851
6297
  }
4852
6298
  ) });
4853
- return /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
4854
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.historySettings }),
4855
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
4856
- /* @__PURE__ */ jsx6(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set("enabled", v) }),
4857
- /* @__PURE__ */ jsx6(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
4858
- !all && /* @__PURE__ */ jsxs4(Checks, { disabled: disabled || !history.enabled, children: [
4859
- /* @__PURE__ */ jsx6("legend", { children: t.historyTypes }),
4860
- types.map((type) => /* @__PURE__ */ jsxs4("label", { children: [
4861
- /* @__PURE__ */ jsx6(
6299
+ return /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "history-settings", children: [
6300
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.historySettings }),
6301
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.historySettingsHelp }),
6302
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "history-enabled", label: t.historyEnabled, value: history.enabled, disabled, onChange: (v) => set2("enabled", v) }),
6303
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "history-all", label: t.historyAll, value: all, disabled: disabled || !history.enabled, onChange: (v) => set2("contentTypes", v ? "all" : types.map((type) => type.uid)) }),
6304
+ !all && /* @__PURE__ */ jsxs5(Checks, { disabled: disabled || !history.enabled, children: [
6305
+ /* @__PURE__ */ jsx7("legend", { children: t.historyTypes }),
6306
+ types.map((type) => /* @__PURE__ */ jsxs5("label", { children: [
6307
+ /* @__PURE__ */ jsx7(
4862
6308
  "input",
4863
6309
  {
4864
6310
  type: "checkbox",
4865
6311
  name: `history-type-${type.uid}`,
4866
6312
  checked: list.includes(type.uid),
4867
- onChange: (e) => set("contentTypes", e.target.checked ? [...list, type.uid] : list.filter((uid) => uid !== type.uid))
6313
+ onChange: (e) => set2("contentTypes", e.target.checked ? [...list, type.uid] : list.filter((uid) => uid !== type.uid))
4868
6314
  }
4869
6315
  ),
4870
6316
  type.displayName
4871
6317
  ] }, type.uid))
4872
6318
  ] }),
4873
- /* @__PURE__ */ jsxs4(Flex3, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
6319
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 4, wrap: "wrap", alignItems: "flex-end", children: [
4874
6320
  number("retentionDays"),
4875
6321
  number("maxSnapshots"),
4876
- number("eventDays")
6322
+ number("eventDays"),
6323
+ number("trashDays")
4877
6324
  ] }),
4878
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : t.historyRetentionHelp })
6325
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: badRetention(history) ? "danger600" : "neutral600", role: badRetention(history) ? "alert" : void 0, children: badRetention(history) ? t.historyInvalid : `${t.historyRetentionHelp} ${t.trashDaysHelp}` })
4879
6326
  ] }) });
4880
6327
  }
4881
- function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
4882
- const items = entry.sidebar || [];
4883
- const save = (next) => set("sidebar", next.length ? next : void 0, void 0);
4884
- const edit = (index, patch) => save(items.map((item, i) => i === index ? { ...item, ...patch } : item));
6328
+ function SidebarEditor({ type, entry, set: set2, t, disabled, SelectField: SelectField2, TextField: TextField2 }) {
6329
+ const items2 = entry.sidebar || [];
6330
+ const save = (next) => set2("sidebar", next.length ? next : void 0, void 0);
6331
+ const edit = (index, patch) => save(items2.map((item, i) => i === index ? { ...item, ...patch } : item));
4885
6332
  const move = (index, by) => {
4886
- const next = [...items];
6333
+ const next = [...items2];
4887
6334
  [next[index], next[index + by]] = [next[index + by], next[index]];
4888
6335
  save(next);
4889
6336
  };
4890
6337
  const fields = (type.attributes || []).filter((attr) => !SYSTEM_FIELDS2.includes(attr.name));
4891
6338
  const id = (name, index) => `sidebar-${name}-${type.uid}${index === void 0 ? "" : `-${index}`}`;
4892
- return /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
4893
- /* @__PURE__ */ jsx6(Typography3, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
4894
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
4895
- /* @__PURE__ */ jsx6(Box2, { style: { maxWidth: 240 }, children: /* @__PURE__ */ jsx6(
6339
+ return /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, "data-testid": `sidebar-editor-${type.uid}`, children: [
6340
+ /* @__PURE__ */ jsx7(Typography3, { variant: "delta", tag: "h3", children: t.f("sidebarTitle", { name: type.displayName }) }),
6341
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.sidebarHelp }),
6342
+ /* @__PURE__ */ jsx7(Box2, { style: { maxWidth: 240 }, children: /* @__PURE__ */ jsx7(
4896
6343
  SelectField2,
4897
6344
  {
4898
6345
  name: id("position"),
@@ -4900,24 +6347,24 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4900
6347
  value: entry.sidebarPosition || "left",
4901
6348
  disabled,
4902
6349
  options: ["left", "right", "bottom"].map((value) => ({ value, label: t.positions[value] })),
4903
- onChange: (v) => set("sidebarPosition", v, "left")
6350
+ onChange: (v) => set2("sidebarPosition", v, "left")
4904
6351
  }
4905
6352
  ) }),
4906
- items.map((item, index) => /* @__PURE__ */ jsxs4(Item, { "data-testid": id("item", index), children: [
4907
- /* @__PURE__ */ jsxs4(Flex3, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
4908
- /* @__PURE__ */ jsx6(Box2, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ jsx6(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
4909
- /* @__PURE__ */ jsx6(Box2, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx6(
6353
+ items2.map((item, index) => /* @__PURE__ */ jsxs5(Item, { "data-testid": id("item", index), children: [
6354
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 4, alignItems: "flex-end", wrap: "wrap", children: [
6355
+ /* @__PURE__ */ jsx7(Box2, { style: { flex: "1 1 200px" }, children: /* @__PURE__ */ jsx7(TextField2, { name: id("label", index), label: t.sidebarItemLabel, value: item.label, disabled, onChange: (v) => edit(index, { label: v }) }) }),
6356
+ /* @__PURE__ */ jsx7(Box2, { style: { minWidth: 180 }, children: /* @__PURE__ */ jsx7(
4910
6357
  SelectField2,
4911
6358
  {
4912
6359
  name: id("icon", index),
4913
6360
  label: t.sidebarIcon,
4914
6361
  value: item.icon || "none",
4915
6362
  disabled,
4916
- options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ jsx6(Icon, { name: value, size: 16 }) }))],
6363
+ options: [{ value: "none", label: t.noIcon }, ...SIDEBAR_ICONS.map((value) => ({ value, label: t.icons[value], icon: /* @__PURE__ */ jsx7(Icon, { name: value, size: 16 }) }))],
4917
6364
  onChange: (v) => edit(index, { icon: v === "none" ? void 0 : v })
4918
6365
  }
4919
6366
  ) }),
4920
- /* @__PURE__ */ jsx6(Box2, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx6(
6367
+ /* @__PURE__ */ jsx7(Box2, { style: { minWidth: 160 }, children: /* @__PURE__ */ jsx7(
4921
6368
  SelectField2,
4922
6369
  {
4923
6370
  name: id("open", index),
@@ -4928,16 +6375,16 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4928
6375
  onChange: (v) => edit(index, { open: v })
4929
6376
  }
4930
6377
  ) }),
4931
- /* @__PURE__ */ jsxs4(Flex3, { gap: 1, paddingBottom: 1, children: [
4932
- /* @__PURE__ */ jsx6(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
4933
- /* @__PURE__ */ jsx6(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items.length - 1, onClick: () => move(index, 1) }),
4934
- /* @__PURE__ */ jsx6(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items.filter((_, i) => i !== index)) })
6378
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 1, paddingBottom: 1, children: [
6379
+ /* @__PURE__ */ jsx7(Tool, { icon: "up", label: t.moveUp, disabled: disabled || index === 0, onClick: () => move(index, -1) }),
6380
+ /* @__PURE__ */ jsx7(Tool, { icon: "down", label: t.moveDown, disabled: disabled || index === items2.length - 1, onClick: () => move(index, 1) }),
6381
+ /* @__PURE__ */ jsx7(Tool, { icon: "close", label: t.sidebarRemove, disabled, onClick: () => save(items2.filter((_, i) => i !== index)) })
4935
6382
  ] })
4936
6383
  ] }),
4937
- /* @__PURE__ */ jsxs4(Checks, { disabled, children: [
4938
- /* @__PURE__ */ jsx6("legend", { children: t.sidebarFields }),
4939
- fields.map((attr) => /* @__PURE__ */ jsxs4("label", { children: [
4940
- /* @__PURE__ */ jsx6(
6384
+ /* @__PURE__ */ jsxs5(Checks, { disabled, children: [
6385
+ /* @__PURE__ */ jsx7("legend", { children: t.sidebarFields }),
6386
+ fields.map((attr) => /* @__PURE__ */ jsxs5("label", { children: [
6387
+ /* @__PURE__ */ jsx7(
4941
6388
  "input",
4942
6389
  {
4943
6390
  type: "checkbox",
@@ -4949,21 +6396,21 @@ function SidebarEditor({ type, entry, set, t, disabled, SelectField: SelectField
4949
6396
  attr.name
4950
6397
  ] }, attr.name))
4951
6398
  ] }),
4952
- badItem(item) && /* @__PURE__ */ jsx6(Typography3, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
6399
+ badItem(item) && /* @__PURE__ */ jsx7(Typography3, { role: "alert", variant: "pi", textColor: "danger600", children: t.sidebarInvalid })
4953
6400
  ] }, index)),
4954
- /* @__PURE__ */ jsxs4(Flex3, { gap: 2, alignItems: "center", children: [
4955
- /* @__PURE__ */ jsx6(
6401
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 2, alignItems: "center", children: [
6402
+ /* @__PURE__ */ jsx7(
4956
6403
  Button3,
4957
6404
  {
4958
6405
  variant: "secondary",
4959
6406
  size: "S",
4960
- disabled: disabled || items.length >= SIDEBAR_MAX,
6407
+ disabled: disabled || items2.length >= SIDEBAR_MAX,
4961
6408
  "data-testid": id("add"),
4962
- onClick: () => save([...items, { label: "", open: "drawer", fields: [] }]),
6409
+ onClick: () => save([...items2, { label: "", open: "drawer", fields: [] }]),
4963
6410
  children: t.sidebarAdd
4964
6411
  }
4965
6412
  ),
4966
- items.length >= SIDEBAR_MAX && /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
6413
+ items2.length >= SIDEBAR_MAX && /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.f("sidebarLimit", { max: SIDEBAR_MAX }) })
4967
6414
  ] })
4968
6415
  ] });
4969
6416
  }
@@ -4972,18 +6419,18 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
4972
6419
  const t = useMessages();
4973
6420
  const { get, put, del } = useClient();
4974
6421
  const { canRead, canUpdate, isLoading } = usePermissions2();
4975
- const [data, setData] = React5.useState(null);
4976
- const [catalog, setCatalog] = React5.useState(null);
4977
- const [settings, setSettings] = React5.useState(null);
4978
- const [media, setMedia] = React5.useState({});
4979
- const [sources, setSources] = React5.useState({});
4980
- const [dirty, setDirty] = React5.useState(false);
4981
- const [saving, setSaving] = React5.useState(false);
4982
- const [status, setStatus] = React5.useState("");
4983
- const [failed, setFailed] = React5.useState(false);
4984
- const [filter, setFilter] = React5.useState("");
4985
- const [picking, setPicking] = React5.useState(null);
4986
- React5.useEffect(() => {
6422
+ const [data, setData] = React6.useState(null);
6423
+ const [catalog, setCatalog] = React6.useState(null);
6424
+ const [settings, setSettings] = React6.useState(null);
6425
+ const [media, setMedia] = React6.useState({});
6426
+ const [sources, setSources] = React6.useState({});
6427
+ const [dirty, setDirty] = React6.useState(false);
6428
+ const [saving, setSaving] = React6.useState(false);
6429
+ const [status, setStatus] = React6.useState("");
6430
+ const [failed, setFailed] = React6.useState(false);
6431
+ const [filter, setFilter] = React6.useState("");
6432
+ const [picking, setPicking] = React6.useState(null);
6433
+ React6.useEffect(() => {
4987
6434
  if (!canRead || isLoading) return;
4988
6435
  let active = true;
4989
6436
  Promise.all([get("/blockscene/settings"), get("/blockscene/catalog")]).then(([s, c]) => {
@@ -5008,7 +6455,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5008
6455
  const badSidebar = settings && Object.values(settings.contentTypes || {}).some((entry) => (entry.sidebar || []).some(badItem));
5009
6456
  const badLazy = settings && badUids(settings.editor.lazyFields);
5010
6457
  const badHistory = settings && data?.historyTypes && badRetention(settings.history);
5011
- const invalid = badColor || badSidebar || badLazy || badHistory;
6458
+ const badPane = settings && [settings.editor, ...Object.values(settings.contentTypes || {})].some((entry) => entry.previewDevices && badDevices(entry.previewDevices));
6459
+ const invalid = badColor || badSidebar || badLazy || badHistory || badPane;
5012
6460
  const save = async () => {
5013
6461
  if (!settings || invalid || !canUpdate) return;
5014
6462
  setSaving(true);
@@ -5060,36 +6508,36 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5060
6508
  return index === 0 && manual ? t.manual : t.automatic;
5061
6509
  };
5062
6510
  const ready = !isLoading && canRead && !failed && settings && catalog;
5063
- const header = React5.useRef(null);
5064
- const [floating, setFloating] = React5.useState(false);
6511
+ const header = React6.useRef(null);
6512
+ const [floating, setFloating] = React6.useState(false);
5065
6513
  const main = useMainRect(header);
5066
- React5.useEffect(() => {
6514
+ React6.useEffect(() => {
5067
6515
  const el = header.current;
5068
6516
  if (!el || typeof IntersectionObserver === "undefined") return;
5069
6517
  const observer = new IntersectionObserver(([entry]) => setFloating(!entry.isIntersecting && entry.boundingClientRect.top < 0));
5070
6518
  observer.observe(el);
5071
6519
  return () => observer.disconnect();
5072
6520
  }, [ready]);
5073
- const controls = (suffix) => ready && /* @__PURE__ */ jsxs4(Flex3, { gap: 3, alignItems: "center", wrap: "wrap", children: [
5074
- /* @__PURE__ */ jsx6(Typography3, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
5075
- !suffix && /* @__PURE__ */ jsx6(Button3, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
5076
- /* @__PURE__ */ jsx6(Button3, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
6521
+ const controls = (suffix) => ready && /* @__PURE__ */ jsxs5(Flex3, { gap: 3, alignItems: "center", wrap: "wrap", children: [
6522
+ /* @__PURE__ */ jsx7(Typography3, { role: "status", "aria-live": "polite", textColor: dirty ? "warning700" : "neutral600", "data-testid": `${dirty ? "unsaved-indicator" : "save-status"}${suffix}`, children: dirty ? t.unsaved : status || t.noChanges }),
6523
+ !suffix && /* @__PURE__ */ jsx7(Button3, { variant: "tertiary", onClick: restore, disabled: !canUpdate || saving, "data-testid": "restore-blockscene-settings", children: data.projectDefaults ? t.restoreProject : t.resetAll }),
6524
+ /* @__PURE__ */ jsx7(Button3, { onClick: save, disabled: !canUpdate || invalid || !dirty, loading: saving, "data-testid": `save-blockscene-settings${suffix}`, children: t.save })
5077
6525
  ] });
5078
- return /* @__PURE__ */ jsx6(Box2, { padding: 8, background: "neutral100", children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 5, children: [
5079
- /* @__PURE__ */ jsx6("div", { ref: header, children: /* @__PURE__ */ jsxs4(Flex3, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
5080
- /* @__PURE__ */ jsx6(Typography3, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
6526
+ return /* @__PURE__ */ jsx7(Box2, { padding: 8, background: "neutral100", children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 5, children: [
6527
+ /* @__PURE__ */ jsx7("div", { ref: header, children: /* @__PURE__ */ jsxs5(Flex3, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
6528
+ /* @__PURE__ */ jsx7(Typography3, { variant: "alpha", tag: "h1", children: t.settingsTitle }),
5081
6529
  controls("")
5082
6530
  ] }) }),
5083
- floating && main.width > 0 && /* @__PURE__ */ jsx6(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ jsxs4(Flex3, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
5084
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "p", children: t.settingsTitle }),
6531
+ floating && main.width > 0 && /* @__PURE__ */ jsx7(Bar, { style: { left: main.left, width: main.width }, "data-testid": "settings-floating-bar", children: /* @__PURE__ */ jsxs5(Flex3, { gap: 4, alignItems: "center", justifyContent: "space-between", wrap: "wrap", children: [
6532
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "p", children: t.settingsTitle }),
5085
6533
  controls("-floating")
5086
6534
  ] }) }),
5087
- /* @__PURE__ */ jsx6(Typography3, { textColor: "neutral600", children: t.settingsIntro }),
5088
- isLoading ? /* @__PURE__ */ jsx6(Typography3, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ jsx6(Typography3, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ jsx6(Typography3, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ jsx6(Typography3, { children: t.loading }) : /* @__PURE__ */ jsxs4(Fragment4, { children: [
5089
- data.disabled && /* @__PURE__ */ jsx6(Box2, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx6(Typography3, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
5090
- /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
5091
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.palette }),
5092
- /* @__PURE__ */ jsx6(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ jsx6(
6535
+ /* @__PURE__ */ jsx7(Typography3, { textColor: "neutral600", children: t.settingsIntro }),
6536
+ isLoading ? /* @__PURE__ */ jsx7(Typography3, { children: "\u2026" }) : !canRead ? /* @__PURE__ */ jsx7(Typography3, { role: "alert", children: t.denied }) : failed ? /* @__PURE__ */ jsx7(Typography3, { role: "alert", children: t.loadFailed }) : !settings || !catalog ? /* @__PURE__ */ jsx7(Typography3, { children: t.loading }) : /* @__PURE__ */ jsxs5(Fragment6, { children: [
6537
+ data.disabled && /* @__PURE__ */ jsx7(Box2, { padding: 4, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx7(Typography3, { role: "alert", textColor: "warning700", children: t.disabledByServer }) }),
6538
+ /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
6539
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.palette }),
6540
+ /* @__PURE__ */ jsx7(Swatches, { children: Object.keys(DEFAULT_PALETTE).map((key) => /* @__PURE__ */ jsx7(
5093
6541
  ColorField,
5094
6542
  {
5095
6543
  name: `palette-${key}`,
@@ -5103,42 +6551,43 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5103
6551
  },
5104
6552
  key
5105
6553
  )) }),
5106
- badColor && /* @__PURE__ */ jsx6(Typography3, { role: "alert", textColor: "danger600", children: t.invalidColor }),
5107
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
5108
- /* @__PURE__ */ jsx6(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ jsxs4(Flex3, { direction: "column", gap: 1, children: [
5109
- /* @__PURE__ */ jsx6(Box2, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ jsx6(Wireframe, { template, palette: settings.palette }) }),
5110
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
6554
+ badColor && /* @__PURE__ */ jsx7(Typography3, { role: "alert", textColor: "danger600", children: t.invalidColor }),
6555
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewLabel }),
6556
+ /* @__PURE__ */ jsx7(Swatches, { "data-testid": "palette-preview", children: TEMPLATES.map((template) => /* @__PURE__ */ jsxs5(Flex3, { direction: "column", gap: 1, children: [
6557
+ /* @__PURE__ */ jsx7(Box2, { style: { aspectRatio: "16 / 9", overflow: "hidden" }, hasRadius: true, children: /* @__PURE__ */ jsx7(Wireframe, { template, palette: settings.palette }) }),
6558
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.templates[template] })
5111
6559
  ] }, template)) }),
5112
- /* @__PURE__ */ jsx6(Flex3, { children: /* @__PURE__ */ jsx6(Button3, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
6560
+ /* @__PURE__ */ jsx7(Flex3, { children: /* @__PURE__ */ jsx7(Button3, { variant: "tertiary", size: "S", disabled: !canUpdate, onClick: () => update((s) => {
5113
6561
  s.palette = { ...DEFAULT_PALETTE };
5114
6562
  return s;
5115
6563
  }), children: t.resetPalette }) })
5116
6564
  ] }) }),
5117
- /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
5118
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.editor }),
5119
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6565
+ /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
6566
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.editor }),
6567
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-enabled", label: t.enabled, value: editor.enabled, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5120
6568
  s.editor.enabled = v;
5121
6569
  return s;
5122
6570
  }) }),
5123
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
5124
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6571
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.enabledHelp }),
6572
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-showOpenAll", label: t.showOpenAll, value: editor.showOpenAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5125
6573
  s.editor.showOpenAll = v;
5126
6574
  return s;
5127
6575
  }) }),
5128
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6576
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-showCloseAll", label: t.showCloseAll, value: editor.showCloseAll, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5129
6577
  s.editor.showCloseAll = v;
5130
6578
  return s;
5131
6579
  }) }),
5132
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6580
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.toggleHelp }),
6581
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-showRowThumbnails", label: t.showRowThumbnails, value: editor.showRowThumbnails !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5133
6582
  s.editor.showRowThumbnails = v;
5134
6583
  return s;
5135
6584
  }) }),
5136
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6585
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-friendlyLabels", label: t.friendlyLabels, value: editor.friendlyLabels !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5137
6586
  s.editor.friendlyLabels = v;
5138
6587
  return s;
5139
6588
  }) }),
5140
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
5141
- /* @__PURE__ */ jsx6(
6589
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.friendlyLabelsHelp }),
6590
+ /* @__PURE__ */ jsx7(
5142
6591
  SelectField2,
5143
6592
  {
5144
6593
  name: "editor-initialState",
@@ -5152,8 +6601,8 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5152
6601
  })
5153
6602
  }
5154
6603
  ),
5155
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
5156
- /* @__PURE__ */ jsx6(
6604
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.rememberHelp }),
6605
+ /* @__PURE__ */ jsx7(
5157
6606
  TextField2,
5158
6607
  {
5159
6608
  name: "editor-blockPreviewUrl",
@@ -5167,9 +6616,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5167
6616
  })
5168
6617
  }
5169
6618
  ),
5170
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
5171
- previewSupported ? /* @__PURE__ */ jsxs4(Fragment4, { children: [
5172
- /* @__PURE__ */ jsx6(
6619
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.blockPreviewUrlHelp }),
6620
+ previewSupported ? /* @__PURE__ */ jsxs5(Fragment6, { children: [
6621
+ /* @__PURE__ */ jsx7(
5173
6622
  TextField2,
5174
6623
  {
5175
6624
  name: "editor-previewUrl",
@@ -5183,8 +6632,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5183
6632
  })
5184
6633
  }
5185
6634
  ),
5186
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
5187
- /* @__PURE__ */ jsx6(
6635
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewUrlHelp }),
6636
+ !editor.previewUrl && /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "warning700", "data-testid": "preview-url-empty", children: t.previewUrlEmpty }),
6637
+ /* @__PURE__ */ jsx7(
5188
6638
  SelectField2,
5189
6639
  {
5190
6640
  name: "editor-previewMode",
@@ -5198,12 +6648,28 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5198
6648
  })
5199
6649
  }
5200
6650
  ),
5201
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
5202
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6651
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewModeHelp }),
6652
+ /* @__PURE__ */ jsx7(Typography3, { variant: "delta", tag: "h3", children: t.paneTitle }),
6653
+ /* @__PURE__ */ jsx7(
6654
+ PaneEditor,
6655
+ {
6656
+ id: "editor",
6657
+ toolbar: editor.previewToolbar || TOOLBAR,
6658
+ devices: editor.previewDevices || DEVICE_NAMES,
6659
+ t,
6660
+ disabled: !canUpdate || saving,
6661
+ TextField: TextField2,
6662
+ set: (key, value) => update((s) => {
6663
+ s.editor[key] = value;
6664
+ return s;
6665
+ })
6666
+ }
6667
+ ),
6668
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-lazyEditors", label: t.lazyEditors, value: editor.lazyEditors !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5203
6669
  s.editor.lazyEditors = v;
5204
6670
  return s;
5205
6671
  }) }),
5206
- /* @__PURE__ */ jsx6(
6672
+ /* @__PURE__ */ jsx7(
5207
6673
  UidListField,
5208
6674
  {
5209
6675
  TextField: TextField2,
@@ -5218,31 +6684,31 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5218
6684
  })
5219
6685
  }
5220
6686
  ),
5221
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
5222
- data.blockPreviewAvailable && /* @__PURE__ */ jsxs4(Fragment4, { children: [
5223
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6687
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: badLazy ? "danger600" : "neutral600", role: badLazy ? "alert" : void 0, children: badLazy ? t.f("lazyFieldsInvalid", { max: LAZY_MAX }) : t.lazyEditorsHelp }),
6688
+ data.blockPreviewAvailable && /* @__PURE__ */ jsxs5(Fragment6, { children: [
6689
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-blockPreviewInForm", label: t.blockPreviewInForm, value: editor.blockPreviewInForm, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5224
6690
  s.editor.blockPreviewInForm = v;
5225
6691
  return s;
5226
6692
  }) }),
5227
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
6693
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.blockPreviewInFormHelp })
5228
6694
  ] })
5229
- ] }) : /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
6695
+ ] }) : /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.previewV4 })
5230
6696
  ] }) }),
5231
- /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
5232
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
5233
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6697
+ /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "row-actions-settings", children: [
6698
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.rowActionsTitle }),
6699
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-confirmDelete", label: t.confirmDeleteOption, value: editor.confirmDelete !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5234
6700
  s.editor.confirmDelete = v;
5235
6701
  return s;
5236
6702
  }) }),
5237
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6703
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-duplicate", label: t.duplicateOption, value: editor.duplicate !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5238
6704
  s.editor.duplicate = v;
5239
6705
  return s;
5240
6706
  }) }),
5241
- /* @__PURE__ */ jsx6(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
6707
+ /* @__PURE__ */ jsx7(ToggleField2, { name: "editor-clipboard", label: t.clipboardOption, value: editor.clipboard !== false, disabled: !canUpdate || saving, onChange: (v) => update((s) => {
5242
6708
  s.editor.clipboard = v;
5243
6709
  return s;
5244
6710
  }) }),
5245
- /* @__PURE__ */ jsx6(
6711
+ /* @__PURE__ */ jsx7(
5246
6712
  SelectField2,
5247
6713
  {
5248
6714
  name: "editor-hiddenBlocks",
@@ -5256,9 +6722,9 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5256
6722
  })
5257
6723
  }
5258
6724
  ),
5259
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
6725
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: data.hiddenAttribute ? t.hiddenBlocksHelp : t.hiddenAttributeOff })
5260
6726
  ] }) }),
5261
- data.historyTypes && settings.history && /* @__PURE__ */ jsx6(
6727
+ data.historyTypes && settings.history && /* @__PURE__ */ jsx7(
5262
6728
  HistorySettings,
5263
6729
  {
5264
6730
  types: data.historyTypes,
@@ -5273,12 +6739,12 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5273
6739
  })
5274
6740
  }
5275
6741
  ),
5276
- (data.contentTypes || []).length > 0 && /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
5277
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.contentTypes }),
5278
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
6742
+ (data.contentTypes || []).length > 0 && /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, "data-testid": "content-types", children: [
6743
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.contentTypes }),
6744
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", children: t.contentTypesHelp }),
5279
6745
  data.contentTypes.map((type) => {
5280
6746
  const entry = settings.contentTypes?.[type.uid] || {};
5281
- const set = (key, value, fallback) => update((s) => {
6747
+ const set2 = (key, value, fallback) => update((s) => {
5282
6748
  const next = { ...s.contentTypes?.[type.uid] || {} };
5283
6749
  if (value === fallback) delete next[key];
5284
6750
  else next[key] = value;
@@ -5287,19 +6753,19 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5287
6753
  else delete s.contentTypes[type.uid];
5288
6754
  return s;
5289
6755
  });
5290
- return /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
5291
- /* @__PURE__ */ jsxs4(Flex3, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
5292
- /* @__PURE__ */ jsx6(Box2, { style: { minWidth: 220 }, children: /* @__PURE__ */ jsx6(
6756
+ return /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
6757
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 6, alignItems: "flex-end", wrap: "wrap", "data-testid": `content-type-${type.uid}`, children: [
6758
+ /* @__PURE__ */ jsx7(Box2, { style: { minWidth: 220 }, children: /* @__PURE__ */ jsx7(
5293
6759
  ToggleField2,
5294
6760
  {
5295
6761
  name: `type-enabled-${type.uid}`,
5296
6762
  label: type.displayName,
5297
6763
  value: entry.enabled !== false,
5298
6764
  disabled: !canUpdate || saving,
5299
- onChange: (v) => set("enabled", v, true)
6765
+ onChange: (v) => set2("enabled", v, true)
5300
6766
  }
5301
6767
  ) }),
5302
- previewSupported && /* @__PURE__ */ jsx6(Box2, { style: { minWidth: 240 }, children: /* @__PURE__ */ jsx6(
6768
+ previewSupported && /* @__PURE__ */ jsx7(Box2, { style: { minWidth: 240 }, children: /* @__PURE__ */ jsx7(
5303
6769
  SelectField2,
5304
6770
  {
5305
6771
  name: `type-mode-${type.uid}`,
@@ -5307,25 +6773,52 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5307
6773
  value: entry.previewMode || "default",
5308
6774
  disabled: !canUpdate || saving || entry.enabled === false,
5309
6775
  options: [{ value: "default", label: t.f("modeDefault", { mode: t.modes[editor.previewMode || "form"] }) }, ...["form", "split", "preview"].map((value) => ({ value, label: t.modes[value] }))],
5310
- onChange: (v) => set("previewMode", v, "default")
6776
+ onChange: (v) => set2("previewMode", v, "default")
5311
6777
  }
5312
6778
  ) })
5313
6779
  ] }),
5314
- previewSupported && entry.enabled !== false && /* @__PURE__ */ jsx6(SidebarEditor, { type, entry, set, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 })
6780
+ previewSupported && entry.enabled !== false && /* @__PURE__ */ jsx7(SidebarEditor, { type, entry, set: set2, t, disabled: !canUpdate || saving, SelectField: SelectField2, TextField: TextField2 }),
6781
+ previewSupported && entry.enabled !== false && /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 3, paddingLeft: 4, children: [
6782
+ /* @__PURE__ */ jsx7(
6783
+ ToggleField2,
6784
+ {
6785
+ name: `type-pane-${type.uid}`,
6786
+ label: t.f("paneTypeOverride", { name: type.displayName }),
6787
+ value: Boolean(entry.previewToolbar || entry.previewDevices),
6788
+ disabled: !canUpdate || saving,
6789
+ onChange: (v) => {
6790
+ set2("previewToolbar", v ? [...editor.previewToolbar || TOOLBAR] : void 0, void 0);
6791
+ set2("previewDevices", v ? structuredClone(editor.previewDevices || DEVICE_NAMES) : void 0, void 0);
6792
+ }
6793
+ }
6794
+ ),
6795
+ (entry.previewToolbar || entry.previewDevices) && /* @__PURE__ */ jsx7(
6796
+ PaneEditor,
6797
+ {
6798
+ id: `type-${type.uid}`,
6799
+ toolbar: entry.previewToolbar || editor.previewToolbar || TOOLBAR,
6800
+ devices: entry.previewDevices || editor.previewDevices || DEVICE_NAMES,
6801
+ t,
6802
+ disabled: !canUpdate || saving,
6803
+ TextField: TextField2,
6804
+ set: (key, value) => set2(key, value, void 0)
6805
+ }
6806
+ )
6807
+ ] })
5315
6808
  ] }, type.uid);
5316
6809
  }),
5317
- badSidebar && /* @__PURE__ */ jsx6(Typography3, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
6810
+ badSidebar && /* @__PURE__ */ jsx7(Typography3, { role: "alert", textColor: "danger600", children: t.sidebarInvalidSave })
5318
6811
  ] }) }),
5319
- /* @__PURE__ */ jsx6(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
5320
- /* @__PURE__ */ jsx6(Typography3, { variant: "beta", tag: "h2", children: t.components }),
5321
- /* @__PURE__ */ jsx6(Searchbar2, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
5322
- /* @__PURE__ */ jsx6(Typography3, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
5323
- /* @__PURE__ */ jsx6(Grid, { "data-testid": "components-grid", children: components.map((component) => {
6812
+ /* @__PURE__ */ jsx7(Box2, { padding: 6, background: "neutral0", hasRadius: true, children: /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "stretch", gap: 4, children: [
6813
+ /* @__PURE__ */ jsx7(Typography3, { variant: "beta", tag: "h2", children: t.components }),
6814
+ /* @__PURE__ */ jsx7(Searchbar2, { name: "component-filter", value: filter, placeholder: t.filter, clearLabel: t.clear, onClear: () => setFilter(""), onChange: (e) => setFilter(e.target.value), children: t.filter }),
6815
+ /* @__PURE__ */ jsx7(Typography3, { variant: "pi", textColor: "neutral600", "data-testid": "components-count", children: t.f("countAll", { count: components.length }) }),
6816
+ /* @__PURE__ */ jsx7(Grid, { "data-testid": "components-grid", children: components.map((component) => {
5324
6817
  const entry = settings.components[component.uid] || {};
5325
6818
  const meta = { ...catalog.components?.[component.uid] || {}, ...media[component.uid] || {} };
5326
6819
  const candidates = candidatesFor(component.uid, meta, catalog);
5327
- return /* @__PURE__ */ jsxs4(Card2, { "data-testid": `settings-${component.uid}`, children: [
5328
- /* @__PURE__ */ jsx6(
6820
+ return /* @__PURE__ */ jsxs5(Card2, { "data-testid": `settings-${component.uid}`, children: [
6821
+ /* @__PURE__ */ jsx7(
5329
6822
  Thumb,
5330
6823
  {
5331
6824
  candidates,
@@ -5336,23 +6829,23 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5336
6829
  onResolved: (index) => setSources((current) => current[component.uid] === index ? current : { ...current, [component.uid]: index })
5337
6830
  }
5338
6831
  ),
5339
- /* @__PURE__ */ jsxs4(Flex3, { direction: "column", alignItems: "flex-start", gap: 2, children: [
5340
- /* @__PURE__ */ jsx6(Typography3, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
5341
- /* @__PURE__ */ jsxs4(Typography3, { variant: "pi", textColor: "neutral600", children: [
6832
+ /* @__PURE__ */ jsxs5(Flex3, { direction: "column", alignItems: "flex-start", gap: 2, children: [
6833
+ /* @__PURE__ */ jsx7(Typography3, { fontWeight: "bold", textColor: "neutral800", children: component.displayName }),
6834
+ /* @__PURE__ */ jsxs5(Typography3, { variant: "pi", textColor: "neutral600", children: [
5342
6835
  component.uid,
5343
6836
  " \xB7 ",
5344
6837
  component.category
5345
6838
  ] }),
5346
- /* @__PURE__ */ jsxs4(Typography3, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
6839
+ /* @__PURE__ */ jsxs5(Typography3, { variant: "pi", "data-testid": `source-${component.uid}`, children: [
5347
6840
  t.source,
5348
6841
  ": ",
5349
6842
  sourceOf(component.uid, Boolean(meta.manualImage)),
5350
6843
  meta.manualName ? ` (${meta.manualName})` : ""
5351
6844
  ] }),
5352
- meta.manualMissing && /* @__PURE__ */ jsx6(Typography3, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
5353
- /* @__PURE__ */ jsxs4(Flex3, { gap: 2, wrap: "wrap", children: [
5354
- /* @__PURE__ */ jsx6(Button3, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
5355
- entry.mediaId && /* @__PURE__ */ jsx6(Button3, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
6845
+ meta.manualMissing && /* @__PURE__ */ jsx7(Typography3, { variant: "pi", role: "alert", textColor: "danger600", children: t.brokenMedia }),
6846
+ /* @__PURE__ */ jsxs5(Flex3, { gap: 2, wrap: "wrap", children: [
6847
+ /* @__PURE__ */ jsx7(Button3, { variant: "secondary", size: "S", disabled: !canUpdate || saving, onClick: () => setPicking(component.uid), children: entry.mediaId ? t.replace : t.choose }),
6848
+ entry.mediaId && /* @__PURE__ */ jsx7(Button3, { variant: "tertiary", size: "S", disabled: !canUpdate || saving, onClick: () => {
5356
6849
  update((s) => {
5357
6850
  delete s.components[component.uid]?.mediaId;
5358
6851
  if (!Object.keys(s.components[component.uid] || {}).length) delete s.components[component.uid];
@@ -5365,7 +6858,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5365
6858
  });
5366
6859
  }, children: t.useAutomatic })
5367
6860
  ] }),
5368
- /* @__PURE__ */ jsx6(
6861
+ /* @__PURE__ */ jsx7(
5369
6862
  SelectField2,
5370
6863
  {
5371
6864
  name: `template-${component.uid}`,
@@ -5379,7 +6872,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5379
6872
  })
5380
6873
  }
5381
6874
  ),
5382
- /* @__PURE__ */ jsx6(
6875
+ /* @__PURE__ */ jsx7(
5383
6876
  SelectField2,
5384
6877
  {
5385
6878
  name: `typology-${component.uid}`,
@@ -5390,7 +6883,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5390
6883
  onChange: (v) => setComponent(component.uid, "typology", v === "auto" ? void 0 : v)
5391
6884
  }
5392
6885
  ),
5393
- /* @__PURE__ */ jsx6(
6886
+ /* @__PURE__ */ jsx7(
5394
6887
  TagsField,
5395
6888
  {
5396
6889
  name: `tags-${component.uid}`,
@@ -5405,7 +6898,7 @@ function Settings({ useClient, usePermissions: usePermissions2, MediaPicker: Med
5405
6898
  ] }, component.uid);
5406
6899
  }) })
5407
6900
  ] }) }),
5408
- picking && /* @__PURE__ */ jsx6(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
6901
+ picking && /* @__PURE__ */ jsx7(MediaPicker2, { onClose: () => setPicking(null), onSelect: (asset) => {
5409
6902
  const uid = picking;
5410
6903
  setPicking(null);
5411
6904
  if (!asset?.id) return;
@@ -5434,16 +6927,41 @@ function register(app, Component2, to) {
5434
6927
  }
5435
6928
 
5436
6929
  // admin/catalog.ts
5437
- import * as React6 from "react";
6930
+ import * as React8 from "react";
6931
+
6932
+ // admin/FieldHelp.tsx
6933
+ import * as React7 from "react";
6934
+ import styled6 from "styled-components";
6935
+ import { Flex as Flex4, Tooltip } from "@strapi/design-system";
6936
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
6937
+ var HelpButton = styled6.button`
6938
+ display: inline-flex; padding: 0; border: 0; border-radius: 50%; background: none; cursor: help; color: inherit;
6939
+ &:hover, &:focus-visible { color: ${({ theme }) => theme.colors.primary600}; }
6940
+ &:focus-visible { outline: 2px solid ${({ theme }) => theme.colors.primary600}; outline-offset: 2px; }
6941
+ `;
6942
+ function FieldHelp({ text, previous, title }) {
6943
+ const m = useMessages();
6944
+ const kept = React7.isValidElement(previous) && previous.props.title ? React7.cloneElement(previous, { title }) : previous;
6945
+ return /* @__PURE__ */ jsxs6(Flex4, { gap: 1, alignItems: "center", children: [
6946
+ kept,
6947
+ /* @__PURE__ */ jsx8(Tooltip, { label: text, style: { maxWidth: 320 }, children: /* @__PURE__ */ jsx8(HelpButton, { type: "button", "aria-label": m.fieldHelp, children: /* @__PURE__ */ jsx8(Icon, { name: "info", size: 14 }) }) })
6948
+ ] });
6949
+ }
6950
+ var helpAction = (text, previous) => /* @__PURE__ */ jsx8(FieldHelp, { text, previous, title: React7.isValidElement(previous) && previous.props.title || { id: "blockscene.fieldHelp" } });
6951
+
6952
+ // admin/catalog.ts
5438
6953
  var cached = null;
5439
6954
  var pending = null;
5440
- var load = (get) => get("/blockscene/catalog").then(({ data }) => {
6955
+ var flight = null;
6956
+ var load = (get) => flight || (flight = get("/blockscene/catalog").then(({ data }) => {
5441
6957
  cached = data;
5442
6958
  return data;
5443
- });
6959
+ }).finally(() => {
6960
+ flight = null;
6961
+ }));
5444
6962
  function useCatalog(get) {
5445
- const [catalog, setCatalog] = React6.useState(null);
5446
- React6.useEffect(() => {
6963
+ const [catalog, setCatalog] = React8.useState(null);
6964
+ React8.useEffect(() => {
5447
6965
  let active = true;
5448
6966
  load(get).then((data) => {
5449
6967
  if (active) setCatalog(data);
@@ -5470,7 +6988,7 @@ var labelsHook = (get, relabel, drop) => (args) => {
5470
6988
  pending = null;
5471
6989
  }));
5472
6990
  const trimmed = drop(args.layout, cached ? cached.hiddenAttribute : "bsHidden");
5473
- const layout = cached ? relabel(trimmed, cached, adminLocale()) : trimmed;
6991
+ const layout = cached ? relabel(trimmed, cached, adminLocale(), helpAction) : trimmed;
5474
6992
  return layout === args.layout ? args : { ...args, layout };
5475
6993
  } catch (error) {
5476
6994
  console.error("[blockscene] field labels skipped after an error:", error);
@@ -5479,14 +6997,14 @@ var labelsHook = (get, relabel, drop) => (args) => {
5479
6997
  };
5480
6998
 
5481
6999
  // admin/Guard.tsx
5482
- import * as React7 from "react";
7000
+ import * as React9 from "react";
5483
7001
  import { Box as Box3, Typography as Typography4 } from "@strapi/design-system";
5484
- import { jsx as jsx7 } from "react/jsx-runtime";
7002
+ import { jsx as jsx9 } from "react/jsx-runtime";
5485
7003
  var Notice = () => {
5486
7004
  const t = useMessages();
5487
- return /* @__PURE__ */ jsx7(Box3, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx7(Typography4, { variant: "pi", textColor: "warning700", role: "alert", children: t.crashed }) });
7005
+ return /* @__PURE__ */ jsx9(Box3, { padding: 3, background: "warning100", hasRadius: true, children: /* @__PURE__ */ jsx9(Typography4, { variant: "pi", textColor: "warning700", role: "alert", children: t.crashed }) });
5488
7006
  };
5489
- var Guard = class extends React7.Component {
7007
+ var Guard = class extends React9.Component {
5490
7008
  constructor() {
5491
7009
  super(...arguments);
5492
7010
  __publicField(this, "state", { failed: false });
@@ -5498,25 +7016,29 @@ var Guard = class extends React7.Component {
5498
7016
  console.error("[blockscene] disabled for this view after an error:", error);
5499
7017
  }
5500
7018
  render() {
5501
- return this.state.failed ? /* @__PURE__ */ jsx7(Notice, {}) : this.props.children;
7019
+ return this.state.failed ? /* @__PURE__ */ jsx9(Notice, {}) : this.props.children;
5502
7020
  }
5503
7021
  };
5504
7022
 
5505
7023
  // admin/strapi4.tsx
5506
- import { Fragment as Fragment5, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
7024
+ import { Fragment as Fragment7, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
5507
7025
  function Modal({ open, onOpenChange, trigger, title, children, width = "80vw" }) {
5508
- const id = React8.useId();
5509
- return /* @__PURE__ */ jsxs5(Fragment5, { children: [
7026
+ const id = React10.useId();
7027
+ return /* @__PURE__ */ jsxs7(Fragment7, { children: [
5510
7028
  trigger,
5511
- open && /* @__PURE__ */ jsxs5(ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
5512
- /* @__PURE__ */ jsx8(ModalHeader, { children: /* @__PURE__ */ jsx8(Typography5, { id, variant: "beta", children: title }) }),
5513
- /* @__PURE__ */ jsx8(ModalBody, { children })
7029
+ open && /* @__PURE__ */ jsxs7(ModalLayout, { onClose: () => onOpenChange(false), labelledBy: id, width, children: [
7030
+ /* @__PURE__ */ jsx10(ModalHeader, { children: /* @__PURE__ */ jsx10(Typography5, { id, variant: "beta", children: title }) }),
7031
+ /* @__PURE__ */ jsx10(ModalBody, { children })
5514
7032
  ] })
5515
7033
  ] });
5516
7034
  }
7035
+ var Menu2 = ({ label, testid, items: items2 }) => /* @__PURE__ */ jsx10("div", { "data-testid": testid, children: /* @__PURE__ */ jsx10(SimpleMenu, { variant: "tertiary", size: "S", "aria-label": label, title: label, endIcon: null, label: /* @__PURE__ */ jsx10(Icon, { name: "more", size: 16 }), children: items2.map((item) => /* @__PURE__ */ jsx10(MenuItem, { onClick: item.onSelect, "data-testid": item.testid, children: /* @__PURE__ */ jsxs7(Flex5, { as: "span", gap: 2, alignItems: "center", children: [
7036
+ /* @__PURE__ */ jsx10(Icon, { name: item.icon, size: 16 }),
7037
+ item.label
7038
+ ] }) }, item.testid)) }) });
5517
7039
  function useRowForm(c, components) {
5518
7040
  const toggleNotification = useNotification();
5519
- const latest = React8.useRef(c.modifiedData);
7041
+ const latest = React10.useRef(c.modifiedData);
5520
7042
  latest.current = c.modifiedData;
5521
7043
  if (typeof c.onChange !== "function") return null;
5522
7044
  return {
@@ -5524,6 +7046,7 @@ function useRowForm(c, components) {
5524
7046
  locale: c.initialData?.locale || void 0,
5525
7047
  rows: (zone) => Array.isArray(latest.current?.[zone]) ? latest.current[zone] : [],
5526
7048
  setRows: (zone, rows) => c.onChange({ target: { name: zone, value: rows } }),
7049
+ errorRows: (zone) => errorRows(c.formErrors, zone),
5527
7050
  keys: (rows, _at, n) => integerKeys(rows, n),
5528
7051
  notify: (type, message) => toggleNotification({ type, message }),
5529
7052
  prepare: async (rows) => rows.map((row) => cloneRow(row, components))
@@ -5568,7 +7091,7 @@ function Picker() {
5568
7091
  };
5569
7092
  if (!catalog?.editor?.enabled || catalog.contentTypes?.[c.slug]?.enabled === false) return null;
5570
7093
  const docKey = `${c.slug}:${c.isCreatingEntry ? "new" : c.initialData?.id}:${c.initialData?.locale || ""}`;
5571
- return /* @__PURE__ */ jsx8(
7094
+ return /* @__PURE__ */ jsx10("div", { hidden: true, "data-blockscene-editor": "", children: /* @__PURE__ */ jsx10(
5572
7095
  Gallery,
5573
7096
  {
5574
7097
  zones,
@@ -5583,12 +7106,13 @@ function Picker() {
5583
7106
  docKey,
5584
7107
  contentType: c.slug,
5585
7108
  userId: auth.getUserInfo?.()?.id,
5586
- form
7109
+ form,
7110
+ Menu: Menu2
5587
7111
  }
5588
- );
7112
+ ) });
5589
7113
  }
5590
- var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ jsxs5(Flex4, { gap: 3, children: [
5591
- /* @__PURE__ */ jsx8(
7114
+ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ */ jsxs7(Flex5, { gap: 3, children: [
7115
+ /* @__PURE__ */ jsx10(
5592
7116
  Switch,
5593
7117
  {
5594
7118
  name,
@@ -5598,9 +7122,9 @@ var ToggleField = ({ name, label, value, onChange, disabled }) => /* @__PURE__ *
5598
7122
  onChange: () => onChange(!value)
5599
7123
  }
5600
7124
  ),
5601
- /* @__PURE__ */ jsx8(Typography5, { children: label })
7125
+ /* @__PURE__ */ jsx10(Typography5, { children: label })
5602
7126
  ] });
5603
- var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ jsx8(TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
7127
+ var TextField = ({ name, label, value, onChange, disabled, placeholder }) => /* @__PURE__ */ jsx10(TextInput, { name, label, value, disabled, placeholder, onChange: (e) => onChange(e.target.value) });
5604
7128
  var SelectField = ({
5605
7129
  name,
5606
7130
  label,
@@ -5608,7 +7132,7 @@ var SelectField = ({
5608
7132
  onChange,
5609
7133
  disabled,
5610
7134
  options
5611
- }) => /* @__PURE__ */ jsx8(
7135
+ }) => /* @__PURE__ */ jsx10(
5612
7136
  SingleSelect,
5613
7137
  {
5614
7138
  name,
@@ -5616,7 +7140,7 @@ var SelectField = ({
5616
7140
  value,
5617
7141
  disabled,
5618
7142
  onChange: (v) => onChange(String(v)),
5619
- children: options.map((o) => /* @__PURE__ */ jsx8(SingleSelectOption, { value: o.value, children: o.label }, o.value))
7143
+ children: options.map((o) => /* @__PURE__ */ jsx10(SingleSelectOption, { value: o.value, children: o.label }, o.value))
5620
7144
  }
5621
7145
  );
5622
7146
  function MediaPicker({ onClose, onSelect }) {
@@ -5626,7 +7150,7 @@ function MediaPicker({ onClose, onSelect }) {
5626
7150
  onClose();
5627
7151
  return null;
5628
7152
  }
5629
- return /* @__PURE__ */ jsx8(
7153
+ return /* @__PURE__ */ jsx10(
5630
7154
  Dialog,
5631
7155
  {
5632
7156
  onClose,
@@ -5643,7 +7167,7 @@ function usePermissions() {
5643
7167
  isLoading
5644
7168
  };
5645
7169
  }
5646
- var SettingsPage = () => /* @__PURE__ */ jsx8(Guard, { children: /* @__PURE__ */ jsx8(
7170
+ var SettingsPage = () => /* @__PURE__ */ jsx10(Guard, { children: /* @__PURE__ */ jsx10(
5647
7171
  Settings,
5648
7172
  {
5649
7173
  useClient: useFetchClient,
@@ -5665,7 +7189,7 @@ var strapi4_default = {
5665
7189
  app.registerHook("Admin/CM/pages/EditView/mutate-edit-view-layout", labelsHook(() => getFetchClient().get, labelEditLayout4, dropField4));
5666
7190
  app.injectContentManagerComponent("editView", "right-links", {
5667
7191
  name: "blockscene",
5668
- Component: () => /* @__PURE__ */ jsx8(Guard, { children: /* @__PURE__ */ jsx8(Picker, {}) })
7192
+ Component: () => /* @__PURE__ */ jsx10(Guard, { children: /* @__PURE__ */ jsx10(Picker, {}) })
5669
7193
  });
5670
7194
  }
5671
7195
  };