@blokkli/editor 2.0.0-alpha.46 → 2.0.0-alpha.47

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.
Files changed (74) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +2 -1
  3. package/dist/modules/agent/runtime/app/helpers/validation.d.ts +13 -0
  4. package/dist/modules/agent/runtime/app/helpers/validation.js +22 -0
  5. package/dist/modules/agent/runtime/app/tools/add_content_search_paragraph/index.js +12 -0
  6. package/dist/modules/agent/runtime/app/tools/add_fragment/index.js +12 -1
  7. package/dist/modules/agent/runtime/app/tools/add_media_paragraph/index.js +12 -0
  8. package/dist/modules/agent/runtime/app/tools/add_paragraphs/index.js +10 -0
  9. package/dist/modules/agent/runtime/app/tools/add_reusable_paragraph/index.js +12 -0
  10. package/dist/modules/agent/runtime/app/tools/add_template/index.js +5 -0
  11. package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/index.js +15 -0
  12. package/dist/modules/agent/runtime/app/tools/delete_paragraphs/index.js +12 -0
  13. package/dist/modules/agent/runtime/app/tools/detach_reusable_paragraph/index.js +12 -0
  14. package/dist/modules/agent/runtime/app/tools/duplicate_paragraphs/index.js +16 -1
  15. package/dist/modules/agent/runtime/app/tools/move_paragraphs/index.js +17 -0
  16. package/dist/modules/agent/runtime/app/tools/rearrange_paragraphs/index.js +11 -0
  17. package/dist/modules/agent/runtime/app/tools/replace_content_search_item/index.js +8 -0
  18. package/dist/modules/agent/runtime/app/tools/replace_media_field/index.js +10 -0
  19. package/dist/modules/agent/runtime/app/tools/set_paragraph_options/index.js +10 -0
  20. package/dist/modules/agent/runtime/app/tools/swap_paragraphs/index.js +15 -0
  21. package/dist/modules/agent/runtime/app/tools/update_text_fields/index.js +21 -1
  22. package/dist/modules/agent/runtime/app/types/index.d.ts +6 -6
  23. package/dist/modules/drupal/index.mjs +2 -1
  24. package/dist/modules/drupal/runtime/adapter/index.js +15 -3
  25. package/dist/runtime/editor/components/Actions/index.vue +47 -2
  26. package/dist/runtime/editor/components/AnimationCanvas/index.vue +6 -3
  27. package/dist/runtime/editor/components/BundleSelector/index.d.vue.ts +8 -4
  28. package/dist/runtime/editor/components/BundleSelector/index.vue +111 -13
  29. package/dist/runtime/editor/components/BundleSelector/index.vue.d.ts +8 -4
  30. package/dist/runtime/editor/components/EditProvider.vue +2 -2
  31. package/dist/runtime/editor/components/FlexTextarea/index.vue +8 -1
  32. package/dist/runtime/editor/css/output.css +1 -1
  33. package/dist/runtime/editor/features/add-list/Blocks/index.vue +6 -3
  34. package/dist/runtime/editor/features/analyze/Renderer/index.vue +1 -1
  35. package/dist/runtime/editor/features/block-scheduler/index.vue +7 -1
  36. package/dist/runtime/editor/features/changelog/Dialog/index.vue +1 -1
  37. package/dist/runtime/editor/features/changelog/changelog.json +18 -10
  38. package/dist/runtime/editor/features/clipboard/index.vue +6 -1
  39. package/dist/runtime/editor/features/comments/AddForm/index.d.vue.ts +2 -2
  40. package/dist/runtime/editor/features/comments/AddForm/index.vue.d.ts +2 -2
  41. package/dist/runtime/editor/features/delete/index.vue +17 -2
  42. package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +12 -2
  43. package/dist/runtime/editor/features/dragging-overlay/index.vue +5 -2
  44. package/dist/runtime/editor/features/duplicate/index.vue +23 -7
  45. package/dist/runtime/editor/features/edit/index.vue +29 -8
  46. package/dist/runtime/editor/features/editable-field/index.vue +15 -1
  47. package/dist/runtime/editor/features/fragments/index.vue +5 -2
  48. package/dist/runtime/editor/features/hover/Renderer/index.vue +19 -6
  49. package/dist/runtime/editor/features/hover/Renderer/vertex.glsl +5 -2
  50. package/dist/runtime/editor/features/library/index.vue +52 -8
  51. package/dist/runtime/editor/features/media-library/index.vue +7 -2
  52. package/dist/runtime/editor/features/multi-select/Renderer/index.vue +4 -1
  53. package/dist/runtime/editor/features/search/index.vue +7 -2
  54. package/dist/runtime/editor/features/selection/AddButtons/Renderer/index.vue +1 -1
  55. package/dist/runtime/editor/features/selection/AddButtons/index.vue +26 -2
  56. package/dist/runtime/editor/features/selection/Renderer/index.vue +23 -5
  57. package/dist/runtime/editor/features/selection/Renderer/vertex.glsl +5 -2
  58. package/dist/runtime/editor/features/selection/index.vue +17 -5
  59. package/dist/runtime/editor/features/translations/index.vue +17 -11
  60. package/dist/runtime/editor/helpers/dropTargets/index.d.ts +1 -1
  61. package/dist/runtime/editor/helpers/dropTargets/index.js +2 -2
  62. package/dist/runtime/editor/plugins/ItemAction/index.d.vue.ts +4 -1
  63. package/dist/runtime/editor/plugins/ItemAction/index.vue +9 -3
  64. package/dist/runtime/editor/plugins/ItemAction/index.vue.d.ts +4 -1
  65. package/dist/runtime/editor/providers/permissions.d.ts +22 -1
  66. package/dist/runtime/editor/providers/permissions.js +99 -3
  67. package/dist/runtime/editor/providers/selection.d.ts +2 -1
  68. package/dist/runtime/editor/providers/selection.js +10 -5
  69. package/dist/runtime/editor/translations/de.json +89 -1
  70. package/dist/runtime/editor/translations/fr.json +89 -1
  71. package/dist/runtime/editor/translations/gsw_CH.json +89 -1
  72. package/dist/runtime/editor/translations/it.json +89 -1
  73. package/dist/runtime/editor/types/definitions.d.ts +2 -0
  74. package/package.json +1 -1
@@ -80,7 +80,8 @@ const {
80
80
  $t,
81
81
  state,
82
82
  definitions,
83
- blocks
83
+ blocks,
84
+ permissions
84
85
  } = useBlokkli();
85
86
  function buildItem(element) {
86
87
  const itemBundle = element.dataset.sortliId;
@@ -112,7 +113,7 @@ function determineVisibility(bundle, label) {
112
113
  }
113
114
  const sortedList = computed(() => {
114
115
  const autoAdd = definitions.bundlesWithAutoAdd.value;
115
- return [...props.generallyAvailableBundles].filter((v) => !isInternalBundle(v.id)).map((v) => {
116
+ return [...props.generallyAvailableBundles].filter((v) => !isInternalBundle(v.id)).filter((v) => permissions.checkBlockBundlePermission(v.id, "add")).map((v) => {
116
117
  const isVisible = determineVisibility(v.id, v.label);
117
118
  const isDisabled = !v.id || !props.selectableBundles.includes(v.id);
118
119
  const isAutoAdd = autoAdd.includes(v.id);
@@ -294,7 +295,9 @@ defineCommands(() => {
294
295
  ...getAppendCommands(),
295
296
  ...getInsertCommands(selection.items.value[0]),
296
297
  ...getAppendEndCommands()
297
- ];
298
+ ].filter(
299
+ (v) => v.bundle && permissions.checkBlockBundlePermission(v.bundle, "add")
300
+ );
298
301
  });
299
302
  </script>
300
303
 
@@ -51,7 +51,7 @@ const {
51
51
  readability
52
52
  } = useBlokkli();
53
53
  const showTooltip = computed(() => {
54
- return !ui.isChangingOptions.value && !selection.isMultiSelecting.value && !selection.activeEditableLabel.value;
54
+ return !ui.isChangingOptions.value && !selection.isMultiSelecting.value && !selection.activeEditableLabel.value && !selection.isDragging.value;
55
55
  });
56
56
  const activeId = defineModel({ type: String, ...{
57
57
  default: ""
@@ -79,7 +79,13 @@ const disabled = computed(() => {
79
79
  const hasSupport = selection.bundles.value.some(
80
80
  (bundle) => bundlesWithPublish.value.includes(bundle) || bundlesWithUnpublish.value.includes(bundle)
81
81
  );
82
- return !hasSupport;
82
+ if (!hasSupport) {
83
+ return $t(
84
+ "schedulerNotSupported",
85
+ "Scheduling is not available for this block type."
86
+ );
87
+ }
88
+ return false;
83
89
  });
84
90
  function onClick() {
85
91
  selectedUuids.value = [...selection.uuids.value];
@@ -17,7 +17,7 @@
17
17
  <h2>{{ entry.date }}</h2>
18
18
  <span>{{ entry.version }}</span>
19
19
  </div>
20
- <div v-html="entry.html" class="bk-changelog-entry-content" />
20
+ <div class="bk-changelog-entry-content" v-html="entry.html" />
21
21
  </div>
22
22
  </div>
23
23
  </DialogModal>
@@ -1,42 +1,50 @@
1
1
  [
2
+ {
3
+ "version": "2.0.0-alpha.47",
4
+ "date": "2026-03-18",
5
+ "body": {
6
+ "en": "<h3>New Features</h3>\n<h4>Block permissions</h4>\n<p>Administrators can now restrict which block types individual users are allowed to\ncreate, edit, or delete. Restricted blocks are visually marked in the editor.</p>\n<h4>Fragments in block selector</h4>\n<p>When adding a block before or after a selected block, available fragments are now\nlisted directly in the selector by name. Clicking a fragment adds it immediately\nwithout opening a separate dialog.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The block selector now groups items into separate sections for blocks,\nfragments, and actions, making it easier to find the right entry.</li>\n<li>The block selector adjusts its height to the available viewport space, reducing\nunnecessary scrolling when it opens near the top of the screen.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Fixed the analyze tooltip not being positioned and styled correctly.</li>\n<li>Fixed the tooltip transition playing with the wrong origin when the tooltip\nopens above the anchor.</li>\n<li>Fixed the add button tooltip staying visible while the block selector is open.</li>\n</ul>\n",
7
+ "de": "<h3>Neue Funktionen</h3>\n<h4>Block-Berechtigungen</h4>\n<p>Administratoren können jetzt festlegen, welche Blocktypen einzelne Benutzer\nerstellen, bearbeiten oder löschen dürfen. Eingeschränkte Blöcke werden im\nEditor visuell markiert.</p>\n<h4>Fragmente in der Block-Auswahl</h4>\n<p>Beim Hinzufügen eines Blocks vor oder nach einem ausgewählten Block werden\nverfügbare Fragmente jetzt direkt namentlich in der Auswahl angezeigt. Ein Klick\nauf ein Fragment fügt es sofort hinzu, ohne einen separaten Dialog zu öffnen.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Block-Auswahl zeigt Einträge jetzt in getrennten Bereichen für Blöcke,\nFragmente und Aktionen an, was die Übersicht verbessert.</li>\n<li>Die Block-Auswahl passt ihre Höhe an den verfügbaren Platz im Fenster an, was\nunnötiges Scrollen beim Öffnen im oberen Bildschirmbereich reduziert.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Der Analyse-Tooltip wurde nicht korrekt positioniert und dargestellt.</li>\n<li>Die Tooltip-Animation hatte den falschen Ursprung, wenn der Tooltip oberhalb\ndes Ankers geöffnet wurde.</li>\n<li>Der Tooltip der Hinzufügen-Schaltfläche blieb sichtbar, während die\nBlock-Auswahl geöffnet war.</li>\n</ul>\n"
8
+ }
9
+ },
2
10
  {
3
11
  "version": "2.0.0-alpha.46",
4
12
  "date": "2026-03-13",
5
13
  "body": {
6
- "en": "<h3>New Features</h3>\n<h4>Automatic text replacements</h4>\n<p>When editing text fields, common typographic patterns are now automatically replaced: straight double quotes (&quot;...&quot;) become guillemets («...»), three dots (...) become an ellipsis (…), and double hyphens (--) become an en dash (–). Guillemet replacement is only active for German and French languages. All replacements can be undone with Ctrl+Z.</p>\n<h4>Undo/redo in text fields</h4>\n<p>Text fields now have a proper undo/redo history. Use Ctrl+Z to undo and Ctrl+Shift+Z or Ctrl+Y to redo.</p>\n",
7
- "de": "<h3>Neue Funktionen</h3>\n<h4>Automatische Textersetzungen</h4>\n<p>Beim Bearbeiten von Textfeldern werden häufige typografische Muster automatisch ersetzt: Gerade Anführungszeichen (&quot;...&quot;) werden zu Guillemets («...»), drei Punkte (...) zu einem Auslassungszeichen (…) und doppelte Bindestriche (--) zu einem Gedankenstrich (–). Die Guillemet-Ersetzung ist nur bei deutscher und französischer Sprache aktiv. Alle Ersetzungen können mit Ctrl+Z rückgängig gemacht werden.</p>\n<h4>Rückgängig/Wiederherstellen in Textfeldern</h4>\n<p>Textfelder haben jetzt eine vollständige Rückgängig-/Wiederherstellen-Historie. Mit Ctrl+Z kann rückgängig gemacht und mit Ctrl+Shift+Z oder Ctrl+Y wiederhergestellt werden.</p>\n"
14
+ "en": "<h3>New Features</h3>\n<h4>Automatic text replacements</h4>\n<p>When editing text fields, common typographic patterns are now automatically\nreplaced: straight double quotes (&quot;...&quot;) become guillemets («...»), three dots\n(...) become an ellipsis (…), and double hyphens (--) become an en dash (–).\nGuillemet replacement is only active for German and French languages. All\nreplacements can be undone with Ctrl+Z.</p>\n<h4>Undo/redo in text fields</h4>\n<p>Text fields now have a proper undo/redo history. Use Ctrl+Z to undo and\nCtrl+Shift+Z or Ctrl+Y to redo.</p>\n",
15
+ "de": "<h3>Neue Funktionen</h3>\n<h4>Automatische Textersetzungen</h4>\n<p>Beim Bearbeiten von Textfeldern werden häufige typografische Muster automatisch\nersetzt: Gerade Anführungszeichen (&quot;...&quot;) werden zu Guillemets («...»), drei\nPunkte (...) zu einem Auslassungszeichen (…) und doppelte Bindestriche (--) zu\neinem Gedankenstrich (–). Die Guillemet-Ersetzung ist nur bei deutscher und\nfranzösischer Sprache aktiv. Alle Ersetzungen können mit Ctrl+Z rückgängig\ngemacht werden.</p>\n<h4>Rückgängig/Wiederherstellen in Textfeldern</h4>\n<p>Textfelder haben jetzt eine vollständige Rückgängig-/Wiederherstellen-Historie.\nMit Ctrl+Z kann rückgängig gemacht und mit Ctrl+Shift+Z oder Ctrl+Y\nwiederhergestellt werden.</p>\n"
8
16
  }
9
17
  },
10
18
  {
11
19
  "version": "2.0.0-alpha.44",
12
20
  "date": "2026-03-12",
13
21
  "body": {
14
- "en": "<h3>New Features</h3>\n<h4>Heading structure analyzer</h4>\n<p>A new built-in analyzer checks the heading hierarchy on your page (H1–H6) and flags issues such as multiple H1 headings or skipped heading levels.</p>\n<h4>Image alt text analyzer</h4>\n<p>A new accessibility analyzer highlights images that are missing alt text directly on the page.</p>\n<h4>Analyze tooltips on the artboard</h4>\n<p>When the analyze panel is active, hovering over a highlighted element now shows a tooltip with the issue title and readability score.</p>\n<h4>Readability score in editable overlay</h4>\n<p>While editing a rich text field, the readability score for the full text is now shown in the editing toolbar above the field.</p>\n<h4>Select parent block button</h4>\n<p>The block actions toolbar now has a button that lets you quickly select the enclosing parent block.</p>\n<h4>Move block button</h4>\n<p>A drag handle button in the actions toolbar lets you start moving blocks directly from the toolbar.</p>\n<h4>Improved search when adding blocks</h4>\n<p>The block selector now finds the right block type even with typos or partial terms. The search field is also focused automatically when the selector opens.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The &quot;Keep results visible&quot; toggle in the analyze panel now shows a description explaining that results stay highlighted even after the panel is closed.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Fixed the edit indicator not rendering after entering edit mode.</li>\n<li>Fixed the sticky block actions toolbar sometimes jumping to the wrong position.</li>\n<li>Fixed a visual glitch in the selection when the page was selected and the context menu was opened.</li>\n<li>Fixed block options changes not being submitted when a dialog was opened.</li>\n<li>Fixed the language switcher being shown even when only one language is available.</li>\n<li>Fixed readability scores being calculated incorrectly for certain text fields.</li>\n<li>Improved the readability analysis for German texts.</li>\n</ul>\n",
15
- "de": "<h3>Neue Funktionen</h3>\n<h4>Überschriftenstruktur-Analyse</h4>\n<p>Eine neue Prüfung kontrolliert die Überschriftenstruktur auf der Seite (H1–H6) und markiert Probleme wie mehrfache H1-Überschriften oder übersprungene Ebenen.</p>\n<h4>Alt-Text-Analyse für Bilder</h4>\n<p>Eine neue Barrierefreiheits-Prüfung hebt Bilder ohne Alt-Text direkt auf der Seite hervor.</p>\n<h4>Analyse-Tooltips auf der Seite</h4>\n<p>Wenn das Analyse-Panel aktiv ist, erscheint beim Hovern über ein markiertes Element ein Tooltip mit dem Titel des Problems und dem Lesbarkeitswert.</p>\n<h4>Lesbarkeitswert in der Bearbeitungsansicht</h4>\n<p>Beim Bearbeiten eines Rich-Text-Feldes wird der Lesbarkeitswert in der Werkzeugleiste oberhalb des Feldes angezeigt.</p>\n<h4>Übergeordneten Block auswählen</h4>\n<p>Die Block-Aktionsleiste hat jetzt eine Schaltfläche, um schnell den übergeordneten Block auszuwählen.</p>\n<h4>Block-Verschieben-Schaltfläche</h4>\n<p>Ein Ziehpunkt in der Aktionsleiste ermöglicht das direkte Verschieben von Blöcken.</p>\n<h4>Verbesserte Suche beim Hinzufügen von Blöcken</h4>\n<p>Die Block-Auswahl findet jetzt auch bei Tippfehlern den richtigen Blocktyp. Das Suchfeld wird beim Öffnen automatisch fokussiert.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Der Schalter «Ergebnisse sichtbar lassen» im Analyse-Panel zeigt jetzt eine Beschreibung, die erklärt, dass Ergebnisse auch nach dem Schliessen des Panels auf der Seite hervorgehoben bleiben.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Der Bearbeitungsindikator wurde nach dem Wechsel in den Bearbeitungsmodus nicht angezeigt.</li>\n<li>Die fixierte Block-Aktionsleiste sprang manchmal an die falsche Position.</li>\n<li>Ein visueller Fehler bei der Auswahl wurde behoben, der beim gleichzeitigen Öffnen des Kontextmenüs auftrat.</li>\n<li>Block-Optionen wurden beim Öffnen eines Dialogs nicht übermittelt.</li>\n<li>Der Sprachumschalter wurde auch dann angezeigt, wenn nur eine Sprache verfügbar war.</li>\n<li>Lesbarkeitswerte wurden in gewissen Fällen falsch berechnet.</li>\n<li>Die Lesbarkeitsanalyse für deutsche Texte wurde verbessert.</li>\n</ul>\n"
22
+ "en": "<h3>New Features</h3>\n<h4>Heading structure analyzer</h4>\n<p>A new built-in analyzer checks the heading hierarchy on your page (H1–H6) and\nflags issues such as multiple H1 headings or skipped heading levels.</p>\n<h4>Image alt text analyzer</h4>\n<p>A new accessibility analyzer highlights images that are missing alt text\ndirectly on the page.</p>\n<h4>Analyze tooltips on the artboard</h4>\n<p>When the analyze panel is active, hovering over a highlighted element now shows\na tooltip with the issue title and readability score.</p>\n<h4>Readability score in editable overlay</h4>\n<p>While editing a rich text field, the readability score for the full text is now\nshown in the editing toolbar above the field.</p>\n<h4>Select parent block button</h4>\n<p>The block actions toolbar now has a button that lets you quickly select the\nenclosing parent block.</p>\n<h4>Move block button</h4>\n<p>A drag handle button in the actions toolbar lets you start moving blocks\ndirectly from the toolbar.</p>\n<h4>Improved search when adding blocks</h4>\n<p>The block selector now finds the right block type even with typos or partial\nterms. The search field is also focused automatically when the selector opens.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The &quot;Keep results visible&quot; toggle in the analyze panel now shows a description\nexplaining that results stay highlighted even after the panel is closed.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Fixed the edit indicator not rendering after entering edit mode.</li>\n<li>Fixed the sticky block actions toolbar sometimes jumping to the wrong\nposition.</li>\n<li>Fixed a visual glitch in the selection when the page was selected and the\ncontext menu was opened.</li>\n<li>Fixed block options changes not being submitted when a dialog was opened.</li>\n<li>Fixed the language switcher being shown even when only one language is\navailable.</li>\n<li>Fixed readability scores being calculated incorrectly for certain text fields.</li>\n<li>Improved the readability analysis for German texts.</li>\n</ul>\n",
23
+ "de": "<h3>Neue Funktionen</h3>\n<h4>Überschriftenstruktur-Analyse</h4>\n<p>Eine neue Prüfung kontrolliert die Überschriftenstruktur auf der Seite (H1–H6)\nund markiert Probleme wie mehrfache H1-Überschriften oder übersprungene Ebenen.</p>\n<h4>Alt-Text-Analyse für Bilder</h4>\n<p>Eine neue Barrierefreiheits-Prüfung hebt Bilder ohne Alt-Text direkt auf der\nSeite hervor.</p>\n<h4>Analyse-Tooltips auf der Seite</h4>\n<p>Wenn das Analyse-Panel aktiv ist, erscheint beim Hovern über ein markiertes\nElement ein Tooltip mit dem Titel des Problems und dem Lesbarkeitswert.</p>\n<h4>Lesbarkeitswert in der Bearbeitungsansicht</h4>\n<p>Beim Bearbeiten eines Rich-Text-Feldes wird der Lesbarkeitswert in der\nWerkzeugleiste oberhalb des Feldes angezeigt.</p>\n<h4>Übergeordneten Block auswählen</h4>\n<p>Die Block-Aktionsleiste hat jetzt eine Schaltfläche, um schnell den\nübergeordneten Block auszuwählen.</p>\n<h4>Block-Verschieben-Schaltfläche</h4>\n<p>Ein Ziehpunkt in der Aktionsleiste ermöglicht das direkte Verschieben von\nBlöcken.</p>\n<h4>Verbesserte Suche beim Hinzufügen von Blöcken</h4>\n<p>Die Block-Auswahl findet jetzt auch bei Tippfehlern den richtigen Blocktyp. Das\nSuchfeld wird beim Öffnen automatisch fokussiert.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Der Schalter «Ergebnisse sichtbar lassen» im Analyse-Panel zeigt jetzt eine\nBeschreibung, die erklärt, dass Ergebnisse auch nach dem Schliessen des Panels\nauf der Seite hervorgehoben bleiben.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Der Bearbeitungsindikator wurde nach dem Wechsel in den Bearbeitungsmodus\nnicht angezeigt.</li>\n<li>Die fixierte Block-Aktionsleiste sprang manchmal an die falsche Position.</li>\n<li>Ein visueller Fehler bei der Auswahl wurde behoben, der beim gleichzeitigen\nÖffnen des Kontextmenüs auftrat.</li>\n<li>Block-Optionen wurden beim Öffnen eines Dialogs nicht übermittelt.</li>\n<li>Der Sprachumschalter wurde auch dann angezeigt, wenn nur eine Sprache\nverfügbar war.</li>\n<li>Lesbarkeitswerte wurden in gewissen Fällen falsch berechnet.</li>\n<li>Die Lesbarkeitsanalyse für deutsche Texte wurde verbessert.</li>\n</ul>\n"
16
24
  }
17
25
  },
18
26
  {
19
27
  "version": "2.0.0-alpha.39",
20
28
  "date": "2026-02-22",
21
29
  "body": {
22
- "en": "<h3>New Features</h3>\n<h4>AI Assistant file attachments</h4>\n<p>Drag and drop files (including Word documents) directly onto the AI chat panel to attach them as context — the content is automatically extracted and formatted.</p>\n<h4>AI readability analysis</h4>\n<p>The AI assistant can now analyze the page for readability issues and iteratively improve texts based on readability scores.</p>\n<h4>Faster AI responses</h4>\n<p>The assistant now responds faster to the first message of a conversation.</p>\n<h4>AI action details</h4>\n<p>Completed AI actions in the conversation can now show an expandable details panel with additional context.</p>\n<h4>AI welcome popup</h4>\n<p>A welcome popup now introduces new users to the AI assistant when the editor opens.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The AI assistant sidebar button has been moved to the bottom-right of the toolbar and features an animated star icon.</li>\n<li>The &quot;Start new conversation&quot; and &quot;Past conversations&quot; buttons are now shown directly in the input area instead of in a dropdown.</li>\n<li>Double-clicking a complex data option (e.g. chart data) now immediately opens the editor for that option.</li>\n<li>The AI assistant shows a reconnection indicator in the chat when the connection drops temporarily.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Selecting text inside an inline-editable field no longer accidentally closes the editor when releasing the mouse outside the field.</li>\n<li>The middle mouse button no longer interrupts drag-and-drop interactions.</li>\n<li>Incomplete or truncated AI responses are now handled gracefully instead of silently failing.</li>\n</ul>\n",
23
- "de": "<h3>Neue Funktionen</h3>\n<h4>KI-Assistent: Dateianhänge</h4>\n<p>Dateien (inkl. Word-Dokumente) können direkt per Drag &amp; Drop auf den KI-Chat gezogen werden — der Inhalt wird automatisch extrahiert und formatiert.</p>\n<h4>KI-Lesbarkeitsanalyse</h4>\n<p>Der KI-Assistent kann jetzt die Seite auf Lesbarkeitsprobleme prüfen und Texte anhand der Lesbarkeitswerte schrittweise verbessern.</p>\n<h4>Schnellere KI-Antworten</h4>\n<p>Der Assistent antwortet jetzt schneller auf die erste Nachricht eines Gesprächs.</p>\n<h4>KI-Aktionsdetails</h4>\n<p>Abgeschlossene KI-Aktionen im Gesprächsverlauf können jetzt aufgeklappt werden, um mehr Details anzuzeigen.</p>\n<h4>KI-Willkommens-Popup</h4>\n<p>Beim Öffnen des Editors erscheint ein Willkommens-Popup, das neue Nutzer in den KI-Assistenten einführt.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Schaltfläche des KI-Assistenten wurde in die rechte untere Ecke der Werkzeugleiste verschoben und zeigt jetzt ein animiertes Stern-Symbol.</li>\n<li>Die Schaltflächen «Neues Gespräch» und «Vergangene Gespräche» werden jetzt direkt im Eingabebereich angezeigt statt in einem Dropdown.</li>\n<li>Ein Doppelklick auf eine komplexe Datenoption (z. B. Diagrammdaten) öffnet jetzt direkt den zugehörigen Editor.</li>\n<li>Der KI-Assistent zeigt im Chat einen Hinweis an, wenn die Verbindung vorübergehend unterbrochen wird.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Textauswahl in einem Inline-Bearbeitungsfeld schliesst den Editor nicht mehr versehentlich, wenn die Maus ausserhalb des Felds losgelassen wird.</li>\n<li>Die mittlere Maustaste unterbricht Drag-&amp;-Drop-Aktionen nicht mehr.</li>\n<li>Unvollständige oder abgebrochene KI-Antworten werden jetzt korrekt behandelt, anstatt ohne Fehlermeldung abzubrechen.</li>\n</ul>\n"
30
+ "en": "<h3>New Features</h3>\n<h4>AI Assistant file attachments</h4>\n<p>Drag and drop files (including Word documents) directly onto the AI chat panel\nto attach them as context — the content is automatically extracted and\nformatted.</p>\n<h4>AI readability analysis</h4>\n<p>The AI assistant can now analyze the page for readability issues and iteratively\nimprove texts based on readability scores.</p>\n<h4>Faster AI responses</h4>\n<p>The assistant now responds faster to the first message of a conversation.</p>\n<h4>AI action details</h4>\n<p>Completed AI actions in the conversation can now show an expandable details\npanel with additional context.</p>\n<h4>AI welcome popup</h4>\n<p>A welcome popup now introduces new users to the AI assistant when the editor\nopens.</p>\n<h3>Improvements</h3>\n<ul>\n<li>The AI assistant sidebar button has been moved to the bottom-right of the\ntoolbar and features an animated star icon.</li>\n<li>The &quot;Start new conversation&quot; and &quot;Past conversations&quot; buttons are now shown\ndirectly in the input area instead of in a dropdown.</li>\n<li>Double-clicking a complex data option (e.g. chart data) now immediately opens\nthe editor for that option.</li>\n<li>The AI assistant shows a reconnection indicator in the chat when the\nconnection drops temporarily.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Selecting text inside an inline-editable field no longer accidentally closes\nthe editor when releasing the mouse outside the field.</li>\n<li>The middle mouse button no longer interrupts drag-and-drop interactions.</li>\n<li>Incomplete or truncated AI responses are now handled gracefully instead of\nsilently failing.</li>\n</ul>\n",
31
+ "de": "<h3>Neue Funktionen</h3>\n<h4>KI-Assistent: Dateianhänge</h4>\n<p>Dateien (inkl. Word-Dokumente) können direkt per Drag &amp; Drop auf den KI-Chat\ngezogen werden — der Inhalt wird automatisch extrahiert und formatiert.</p>\n<h4>KI-Lesbarkeitsanalyse</h4>\n<p>Der KI-Assistent kann jetzt die Seite auf Lesbarkeitsprobleme prüfen und Texte\nanhand der Lesbarkeitswerte schrittweise verbessern.</p>\n<h4>Schnellere KI-Antworten</h4>\n<p>Der Assistent antwortet jetzt schneller auf die erste Nachricht eines Gesprächs.</p>\n<h4>KI-Aktionsdetails</h4>\n<p>Abgeschlossene KI-Aktionen im Gesprächsverlauf können jetzt aufgeklappt werden,\num mehr Details anzuzeigen.</p>\n<h4>KI-Willkommens-Popup</h4>\n<p>Beim Öffnen des Editors erscheint ein Willkommens-Popup, das neue Nutzer in den\nKI-Assistenten einführt.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Schaltfläche des KI-Assistenten wurde in die rechte untere Ecke der\nWerkzeugleiste verschoben und zeigt jetzt ein animiertes Stern-Symbol.</li>\n<li>Die Schaltflächen «Neues Gespräch» und «Vergangene Gespräche» werden jetzt\ndirekt im Eingabebereich angezeigt statt in einem Dropdown.</li>\n<li>Ein Doppelklick auf eine komplexe Datenoption (z. B. Diagrammdaten) öffnet\njetzt direkt den zugehörigen Editor.</li>\n<li>Der KI-Assistent zeigt im Chat einen Hinweis an, wenn die Verbindung\nvorübergehend unterbrochen wird.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Textauswahl in einem Inline-Bearbeitungsfeld schliesst den Editor nicht mehr\nversehentlich, wenn die Maus ausserhalb des Felds losgelassen wird.</li>\n<li>Die mittlere Maustaste unterbricht Drag-&amp;-Drop-Aktionen nicht mehr.</li>\n<li>Unvollständige oder abgebrochene KI-Antworten werden jetzt korrekt behandelt,\nanstatt ohne Fehlermeldung abzubrechen.</li>\n</ul>\n"
24
32
  }
25
33
  },
26
34
  {
27
35
  "version": "2.0.0-alpha.35",
28
36
  "date": "2026-02-11",
29
37
  "body": {
30
- "en": "<h3>New Features</h3>\n<h4>AI Assistant</h4>\n<p>A new AI-powered assistant is available in the editor sidebar, allowing you to add, move, delete, and rewrite content blocks through a chat interface with support for plans, conversation history, and media selection.</p>\n<h4>Block preview in &quot;Add&quot; panel</h4>\n<p>Hovering a block type in the add panel now shows a tooltip with a preview image and description.</p>\n<h4>Template management</h4>\n<p>A new management view lets you rename and delete saved templates directly from the editor.</p>\n<h4>Charts</h4>\n<p>A new chart block type is available for embedding interactive charts on pages.</p>\n<h4>Table of contents</h4>\n<p>A new table of contents module is available.</p>\n<h3>Improvements</h3>\n<ul>\n<li>You can now hold Ctrl and click to select multiple items in the media library at once.</li>\n<li>Dragged items are now sized more accurately to match the block being moved.</li>\n<li>Drop target areas shrink visually when not hovered, giving a cleaner layout while dragging.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Long option descriptions no longer overflow in the options tooltip.</li>\n<li>Hover detection for overlapping blocks now correctly respects z-index order.</li>\n<li>The default icon is now correctly displayed for fragment blocks.</li>\n<li>Opening the AI assistant from a block action no longer restores a previous conversation; it starts fresh.</li>\n</ul>\n",
31
- "de": "<h3>Neue Funktionen</h3>\n<h4>KI-Assistent</h4>\n<p>Im Editor steht ein neuer KI-Assistent zur Verfügung. Damit können Blöcke per Chat hinzugefügt, verschoben, gelöscht und umgeschrieben werden – inklusive Planung, Gesprächsverlauf und Medienauswahl.</p>\n<h4>Block-Vorschau im «Hinzufügen»-Panel</h4>\n<p>Beim Überfahren eines Blocktyps im Hinzufügen-Panel erscheint ein Tooltip mit Vorschau und Beschreibung.</p>\n<h4>Vorlagenverwaltung</h4>\n<p>In einer neuen Verwaltungsansicht können gespeicherte Vorlagen direkt im Editor umbenannt und gelöscht werden.</p>\n<h4>Diagramme</h4>\n<p>Ein neuer Diagramm-Blocktyp ist verfügbar, um interaktive Diagramme auf Seiten einzubetten.</p>\n<h4>Inhaltsverzeichnis</h4>\n<p>Ein neues Inhaltsverzeichnis-Modul ist verfügbar.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Mit Strg+Klick können jetzt mehrere Elemente in der Medienbibliothek gleichzeitig ausgewählt werden.</li>\n<li>Beim Ziehen werden Elemente jetzt passender in der Grösse des verschobenen Blocks dargestellt.</li>\n<li>Ablagezonen werden kleiner dargestellt, wenn sie nicht aktiv überfahren werden, was beim Ziehen für ein aufgeräumteres Layout sorgt.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Lange Optionsbeschreibungen im Optionen-Tooltip werden jetzt korrekt dargestellt und laufen nicht mehr über.</li>\n<li>Überlappende Blöcke reagieren jetzt korrekt auf Hover-Aktionen.</li>\n<li>Das Standardsymbol für Fragment-Blöcke wird jetzt korrekt angezeigt.</li>\n<li>Der KI-Assistent startet jetzt immer ein neues Gespräch, wenn er über das Dropdown-Menü eines Blocks geöffnet wird.</li>\n</ul>\n"
38
+ "en": "<h3>New Features</h3>\n<h4>AI Assistant</h4>\n<p>A new AI-powered assistant is available in the editor sidebar, allowing you to\nadd, move, delete, and rewrite content blocks through a chat interface with\nsupport for plans, conversation history, and media selection.</p>\n<h4>Block preview in &quot;Add&quot; panel</h4>\n<p>Hovering a block type in the add panel now shows a tooltip with a preview image\nand description.</p>\n<h4>Template management</h4>\n<p>A new management view lets you rename and delete saved templates directly from\nthe editor.</p>\n<h4>Charts</h4>\n<p>A new chart block type is available for embedding interactive charts on pages.</p>\n<h4>Table of contents</h4>\n<p>A new table of contents module is available.</p>\n<h3>Improvements</h3>\n<ul>\n<li>You can now hold Ctrl and click to select multiple items in the media library\nat once.</li>\n<li>Dragged items are now sized more accurately to match the block being moved.</li>\n<li>Drop target areas shrink visually when not hovered, giving a cleaner layout\nwhile dragging.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Long option descriptions no longer overflow in the options tooltip.</li>\n<li>Hover detection for overlapping blocks now correctly respects z-index order.</li>\n<li>The default icon is now correctly displayed for fragment blocks.</li>\n<li>Opening the AI assistant from a block action no longer restores a previous\nconversation; it starts fresh.</li>\n</ul>\n",
39
+ "de": "<h3>Neue Funktionen</h3>\n<h4>KI-Assistent</h4>\n<p>Im Editor steht ein neuer KI-Assistent zur Verfügung. Damit können Blöcke per\nChat hinzugefügt, verschoben, gelöscht und umgeschrieben werden – inklusive\nPlanung, Gesprächsverlauf und Medienauswahl.</p>\n<h4>Block-Vorschau im «Hinzufügen»-Panel</h4>\n<p>Beim Überfahren eines Blocktyps im Hinzufügen-Panel erscheint ein Tooltip mit\nVorschau und Beschreibung.</p>\n<h4>Vorlagenverwaltung</h4>\n<p>In einer neuen Verwaltungsansicht können gespeicherte Vorlagen direkt im Editor\numbenannt und gelöscht werden.</p>\n<h4>Diagramme</h4>\n<p>Ein neuer Diagramm-Blocktyp ist verfügbar, um interaktive Diagramme auf Seiten\neinzubetten.</p>\n<h4>Inhaltsverzeichnis</h4>\n<p>Ein neues Inhaltsverzeichnis-Modul ist verfügbar.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Mit Strg+Klick können jetzt mehrere Elemente in der Medienbibliothek\ngleichzeitig ausgewählt werden.</li>\n<li>Beim Ziehen werden Elemente jetzt passender in der Grösse des verschobenen\nBlocks dargestellt.</li>\n<li>Ablagezonen werden kleiner dargestellt, wenn sie nicht aktiv überfahren\nwerden, was beim Ziehen für ein aufgeräumteres Layout sorgt.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Lange Optionsbeschreibungen im Optionen-Tooltip werden jetzt korrekt\ndargestellt und laufen nicht mehr über.</li>\n<li>Überlappende Blöcke reagieren jetzt korrekt auf Hover-Aktionen.</li>\n<li>Das Standardsymbol für Fragment-Blöcke wird jetzt korrekt angezeigt.</li>\n<li>Der KI-Assistent startet jetzt immer ein neues Gespräch, wenn er über das\nDropdown-Menü eines Blocks geöffnet wird.</li>\n</ul>\n"
32
40
  }
33
41
  },
34
42
  {
35
43
  "version": "2.0.0-alpha.28",
36
44
  "date": "2026-01-01",
37
45
  "body": {
38
- "en": "<h3>New Features</h3>\n<h4>Templates</h4>\n<p>Blocks can now be saved as reusable templates and inserted into any field from the add list, with a manage dialog for browsing, creating, and organizing templates.</p>\n<h4>Selection breadcrumb</h4>\n<p>A breadcrumb bar appears when a block is selected, showing the nesting path and letting you navigate to parent fields or the page with a single click.</p>\n<h4>Empty field buttons when host is selected</h4>\n<p>Quick-add buttons for empty fields now also appear when the page itself is selected, so you can add blocks without first selecting a block.</p>\n<h4>Search in &quot;Add&quot; overlay</h4>\n<p>The overlay that appears when clicking an add button now includes a search field to quickly filter available blocks.</p>\n<h3>Improvements</h3>\n<ul>\n<li>Pressing the space bar while hovering the canvas now activates the move/pan cursor, matching common design tool conventions.</li>\n<li>After duplicating blocks, the duplicated blocks are automatically selected and scrolled into view.</li>\n<li>After deleting a block, the page scrolls to bring the nearest remaining block into view.</li>\n<li>The dragging overlay label now shows the nesting trail (e.g. parent block name) and stays visible at viewport edges.</li>\n<li>The analyze category filter is hidden when there is only one category.</li>\n<li>The app menu now scrolls correctly when the list of items is longer than the visible area.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Fixed the analyze button being shown when no analyzers were available.</li>\n<li>Fixed the transform preview not displaying the result correctly before applying.</li>\n<li>Fixed the add list panel being too tall on small-screen viewports.</li>\n<li>Fixed the &quot;New&quot; label not appearing in the action bar when multiple blocks are selected.</li>\n</ul>\n",
39
- "de": "<h3>Neue Funktionen</h3>\n<h4>Vorlagen</h4>\n<p>Blöcke können jetzt als Vorlagen gespeichert und aus der Hinzufügen-Liste in beliebige Felder eingefügt werden. Ein Dialog zum Verwalten, Durchsuchen und Erstellen von Vorlagen ist ebenfalls verfügbar.</p>\n<h4>Auswahl-Breadcrumb</h4>\n<p>Beim Auswählen eines Blocks erscheint eine Breadcrumb-Leiste, die den Verschachtelungspfad anzeigt. So kann man schnell zu übergeordneten Feldern oder zur Seite navigieren.</p>\n<h4>Leere-Feld-Schaltflächen bei ausgewählter Seite</h4>\n<p>Schnell-Hinzufügen-Schaltflächen für leere Felder erscheinen jetzt auch, wenn die Seite selbst ausgewählt ist.</p>\n<h4>Suche im «Hinzufügen»-Overlay</h4>\n<p>Das Overlay beim Klicken auf eine Hinzufügen-Schaltfläche enthält jetzt ein Suchfeld, um die verfügbaren Blöcke schnell zu filtern.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Leertaste aktiviert über der Arbeitsfläche jetzt den Verschiebe-/Pan-Cursor, wie in gängigen Design-Tools üblich.</li>\n<li>Nach dem Duplizieren werden die neuen Blöcke automatisch ausgewählt und in den Sichtbereich gescrollt.</li>\n<li>Nach dem Löschen eines Blocks scrollt die Seite automatisch zum nächsten verbleibenden Block.</li>\n<li>Das Zieh-Overlay zeigt jetzt den Verschachtelungspfad und bleibt am Viewport-Rand sichtbar.</li>\n<li>Das Dropdown zur Analyse-Kategorieauswahl wird ausgeblendet, wenn nur eine Kategorie vorhanden ist.</li>\n<li>Das App-Menü scrollt jetzt korrekt, wenn die Liste länger als der sichtbare Bereich ist.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Die Analyse-Schaltfläche wurde angezeigt, obwohl keine Analysen verfügbar waren.</li>\n<li>Die Vorschau von Transformationen wurde korrigiert.</li>\n<li>Die Hinzufügen-Liste war auf kleinen Bildschirmen zu gross.</li>\n<li>Die Bezeichnung «Neu» erschien nicht in der Aktionsleiste, wenn mehrere Blöcke ausgewählt waren.</li>\n</ul>\n"
46
+ "en": "<h3>New Features</h3>\n<h4>Templates</h4>\n<p>Blocks can now be saved as reusable templates and inserted into any field from\nthe add list, with a manage dialog for browsing, creating, and organizing\ntemplates.</p>\n<h4>Selection breadcrumb</h4>\n<p>A breadcrumb bar appears when a block is selected, showing the nesting path and\nletting you navigate to parent fields or the page with a single click.</p>\n<h4>Empty field buttons when host is selected</h4>\n<p>Quick-add buttons for empty fields now also appear when the page itself is\nselected, so you can add blocks without first selecting a block.</p>\n<h4>Search in &quot;Add&quot; overlay</h4>\n<p>The overlay that appears when clicking an add button now includes a search field\nto quickly filter available blocks.</p>\n<h3>Improvements</h3>\n<ul>\n<li>Pressing the space bar while hovering the canvas now activates the move/pan\ncursor, matching common design tool conventions.</li>\n<li>After duplicating blocks, the duplicated blocks are automatically selected and\nscrolled into view.</li>\n<li>After deleting a block, the page scrolls to bring the nearest remaining block\ninto view.</li>\n<li>The dragging overlay label now shows the nesting trail (e.g. parent block\nname) and stays visible at viewport edges.</li>\n<li>The analyze category filter is hidden when there is only one category.</li>\n<li>The app menu now scrolls correctly when the list of items is longer than the\nvisible area.</li>\n</ul>\n<h3>Fixes</h3>\n<ul>\n<li>Fixed the analyze button being shown when no analyzers were available.</li>\n<li>Fixed the transform preview not displaying the result correctly before\napplying.</li>\n<li>Fixed the add list panel being too tall on small-screen viewports.</li>\n<li>Fixed the &quot;New&quot; label not appearing in the action bar when multiple blocks are\nselected.</li>\n</ul>\n",
47
+ "de": "<h3>Neue Funktionen</h3>\n<h4>Vorlagen</h4>\n<p>Blöcke können jetzt als Vorlagen gespeichert und aus der Hinzufügen-Liste in\nbeliebige Felder eingefügt werden. Ein Dialog zum Verwalten, Durchsuchen und\nErstellen von Vorlagen ist ebenfalls verfügbar.</p>\n<h4>Auswahl-Breadcrumb</h4>\n<p>Beim Auswählen eines Blocks erscheint eine Breadcrumb-Leiste, die den\nVerschachtelungspfad anzeigt. So kann man schnell zu übergeordneten Feldern oder\nzur Seite navigieren.</p>\n<h4>Leere-Feld-Schaltflächen bei ausgewählter Seite</h4>\n<p>Schnell-Hinzufügen-Schaltflächen für leere Felder erscheinen jetzt auch, wenn\ndie Seite selbst ausgewählt ist.</p>\n<h4>Suche im «Hinzufügen»-Overlay</h4>\n<p>Das Overlay beim Klicken auf eine Hinzufügen-Schaltfläche enthält jetzt ein\nSuchfeld, um die verfügbaren Blöcke schnell zu filtern.</p>\n<h3>Verbesserungen</h3>\n<ul>\n<li>Die Leertaste aktiviert über der Arbeitsfläche jetzt den\nVerschiebe-/Pan-Cursor, wie in gängigen Design-Tools üblich.</li>\n<li>Nach dem Duplizieren werden die neuen Blöcke automatisch ausgewählt und in den\nSichtbereich gescrollt.</li>\n<li>Nach dem Löschen eines Blocks scrollt die Seite automatisch zum nächsten\nverbleibenden Block.</li>\n<li>Das Zieh-Overlay zeigt jetzt den Verschachtelungspfad und bleibt am\nViewport-Rand sichtbar.</li>\n<li>Das Dropdown zur Analyse-Kategorieauswahl wird ausgeblendet, wenn nur eine\nKategorie vorhanden ist.</li>\n<li>Das App-Menü scrollt jetzt korrekt, wenn die Liste länger als der sichtbare\nBereich ist.</li>\n</ul>\n<h3>Fehlerbehebungen</h3>\n<ul>\n<li>Die Analyse-Schaltfläche wurde angezeigt, obwohl keine Analysen verfügbar\nwaren.</li>\n<li>Die Vorschau von Transformationen wurde korrigiert.</li>\n<li>Die Hinzufügen-Liste war auf kleinen Bildschirmen zu gross.</li>\n<li>Die Bezeichnung «Neu» erschien nicht in der Aktionsleiste, wenn mehrere Blöcke\nausgewählt waren.</li>\n</ul>\n"
40
48
  }
41
49
  }
42
50
  ]
@@ -51,7 +51,8 @@ const {
51
51
  blocks,
52
52
  fields,
53
53
  eventBus,
54
- animation
54
+ animation,
55
+ permissions
55
56
  } = useBlokkli();
56
57
  const selectionClipboard = ref([]);
57
58
  const isDirectDrop = ref(false);
@@ -353,6 +354,10 @@ const handleSelectionPaste = (pastedUuids) => {
353
354
  if (!existingBlocks.length) {
354
355
  return;
355
356
  }
357
+ const deniedBundles = existingBlocks.map((b) => b.bundle).filter((bundle) => !permissions.checkBlockBundlePermission(bundle, "add"));
358
+ if (deniedBundles.length) {
359
+ return;
360
+ }
356
361
  if (selection.uuids.value.length !== 1) {
357
362
  startCopyDrag(existingBlocks);
358
363
  return;
@@ -1,11 +1,11 @@
1
1
  declare const __VLS_export: import("vue").DefineComponent<{}, {
2
2
  getComment: () => string;
3
3
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
- close: () => any;
5
4
  add: (comment: string) => any;
5
+ close: () => any;
6
6
  }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
7
- onClose?: (() => any) | undefined;
8
7
  onAdd?: ((comment: string) => any) | undefined;
8
+ onClose?: (() => any) | undefined;
9
9
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
10
10
  declare const _default: typeof __VLS_export;
11
11
  export default _default;
@@ -1,11 +1,11 @@
1
1
  declare const __VLS_export: import("vue").DefineComponent<{}, {
2
2
  getComment: () => string;
3
3
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
- close: () => any;
5
4
  add: (comment: string) => any;
5
+ close: () => any;
6
6
  }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
7
- onClose?: (() => any) | undefined;
8
7
  onAdd?: ((comment: string) => any) | undefined;
8
+ onClose?: (() => any) | undefined;
9
9
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
10
10
  declare const _default: typeof __VLS_export;
11
11
  export default _default;
@@ -3,6 +3,7 @@
3
3
  id="delete"
4
4
  edit-only
5
5
  :title="$t('deleteButton', 'Delete')"
6
+ :disabled="deleteDisabledReason"
6
7
  multiple
7
8
  key-code="Delete"
8
9
  icon="bk_mdi_delete"
@@ -12,10 +13,10 @@
12
13
  </template>
13
14
 
14
15
  <script setup>
15
- import { useBlokkli, defineBlokkliFeature } from "#imports";
16
+ import { useBlokkli, defineBlokkliFeature, computed } from "#imports";
16
17
  import { PluginItemAction } from "#blokkli/editor/plugins";
17
18
  import { itemEntityType } from "#blokkli-build/config";
18
- const { state, $t, eventBus, dom } = useBlokkli();
19
+ const { state, $t, eventBus, dom, selection, permissions } = useBlokkli();
19
20
  const { adapter } = defineBlokkliFeature({
20
21
  id: "delete",
21
22
  icon: "bk_mdi_delete",
@@ -23,6 +24,20 @@ const { adapter } = defineBlokkliFeature({
23
24
  requiredAdapterMethods: ["deleteBlocks"],
24
25
  description: "Provides an action to delete one or more blocks."
25
26
  });
27
+ const deleteDisabledReason = computed(() => {
28
+ const bundles = selection.bundles.value;
29
+ if (!bundles.length) {
30
+ return false;
31
+ }
32
+ const denied = permissions.filterDeniedBundles(bundles, "delete");
33
+ if (denied.length) {
34
+ return $t(
35
+ "deleteNoPermission",
36
+ "You do not have permission to delete this block."
37
+ );
38
+ }
39
+ return false;
40
+ });
26
41
  function getSelectionAfterDelete(items) {
27
42
  if (items.length !== 1) {
28
43
  return;
@@ -56,7 +56,8 @@ const {
56
56
  types,
57
57
  fields,
58
58
  definitions,
59
- context
59
+ context,
60
+ permissions
60
61
  } = useBlokkli();
61
62
  const FIELD_MIN_DRAW_SIZE = 6;
62
63
  const alphaBase = 0.7;
@@ -158,6 +159,11 @@ const emitDrop = async () => {
158
159
  }
159
160
  eventBus.emit("dragging:end");
160
161
  };
162
+ const isDraggingExisting = computed(
163
+ () => props.items.some(
164
+ (item) => item.itemType === "existing" || item.itemType === "existing_structure"
165
+ )
166
+ );
161
167
  const draggingBundles = computed(
162
168
  () => props.items.flatMap((item) => {
163
169
  const bundles = [];
@@ -421,6 +427,9 @@ const buildFieldRect = (key) => {
421
427
  if (!field) {
422
428
  return;
423
429
  }
430
+ if (field.hostEntityType === itemEntityType && (!permissions.checkBlockBundlePermission(field.hostEntityBundle, "edit") || permissions.blockHasRestrictedAncestor(field.hostEntityUuid))) {
431
+ return;
432
+ }
424
433
  const childElements = [...field.element.children];
425
434
  const currentCount = state.getFieldBlockCount(field.key);
426
435
  const canAddChildren = determineCanAddChildren(
@@ -430,7 +439,8 @@ const buildFieldRect = (key) => {
430
439
  currentCount,
431
440
  props.items.length,
432
441
  draggingBundles.value,
433
- draggingFragments.value
442
+ draggingFragments.value,
443
+ isDraggingExisting.value ? void 0 : (bundle) => permissions.checkBlockBundlePermission(bundle, "add")
434
444
  );
435
445
  const orientation = field.dropAlignment || getChildrenOrientation(field.element);
436
446
  const rect = dom.getFieldRect(field.key);
@@ -72,7 +72,8 @@ const {
72
72
  directive,
73
73
  fields,
74
74
  $t,
75
- dragdrop
75
+ dragdrop,
76
+ permissions
76
77
  } = useBlokkli();
77
78
  const bundleSelectorData = ref(null);
78
79
  let bundleSelectorResolve = null;
@@ -180,7 +181,9 @@ const onDrop = async (e) => {
180
181
  };
181
182
  let result;
182
183
  if (handler.resolveBundles) {
183
- const bundles = await handler.resolveBundles(baseCtx);
184
+ const bundles = (await handler.resolveBundles(baseCtx)).filter(
185
+ (b) => permissions.checkBlockBundlePermission(b, "add")
186
+ );
184
187
  if (bundles.length === 0) {
185
188
  return;
186
189
  }
@@ -2,7 +2,7 @@
2
2
  <PluginItemAction
3
3
  id="duplicate"
4
4
  :title="$t('duplicate', 'Duplicate')"
5
- :disabled="!canDuplicate"
5
+ :disabled="duplicateDisabledReason"
6
6
  edit-only
7
7
  meta
8
8
  key-code="D"
@@ -18,7 +18,7 @@ import { computed, useBlokkli, defineBlokkliFeature } from "#imports";
18
18
  import { PluginItemAction } from "#blokkli/editor/plugins";
19
19
  import { getFieldKey } from "#blokkli/helpers";
20
20
  import { getArrayDiff } from "#blokkli/editor/helpers/array";
21
- const { state, $t, selection, types, eventBus } = useBlokkli();
21
+ const { state, $t, selection, types, eventBus, permissions } = useBlokkli();
22
22
  const { adapter } = defineBlokkliFeature({
23
23
  id: "duplicate",
24
24
  icon: "duplicate",
@@ -45,7 +45,7 @@ async function onClick(items) {
45
45
  const firstUuid = diff[0];
46
46
  eventBus.emit("scrollIntoView", { uuid: firstUuid });
47
47
  }
48
- const canDuplicate = computed(() => {
48
+ const duplicateDisabledReason = computed(() => {
49
49
  const blocksByField = {};
50
50
  const fieldsByKey = {};
51
51
  const selectedCount = selection.items.value.length;
@@ -66,7 +66,10 @@ const canDuplicate = computed(() => {
66
66
  }
67
67
  const count = field.list.length;
68
68
  if (fieldConfig.cardinality !== -1 && count >= fieldConfig.cardinality) {
69
- return false;
69
+ return $t(
70
+ "duplicateFieldFull",
71
+ "The field has reached its maximum number of blocks."
72
+ );
70
73
  }
71
74
  if (!blocksByField[fieldKey]) {
72
75
  blocksByField[fieldKey] = [];
@@ -87,14 +90,27 @@ const canDuplicate = computed(() => {
87
90
  }
88
91
  const count = state.getFieldBlockCount(fieldKey);
89
92
  if (field.cardinality !== -1 && count + blocks.length > field.cardinality) {
90
- return false;
93
+ return $t(
94
+ "duplicateFieldFull",
95
+ "The field has reached its maximum number of blocks."
96
+ );
91
97
  }
92
98
  const bundles = blocks.map((v) => v.bundle);
99
+ const denied = permissions.filterDeniedBundles(bundles, "add");
100
+ if (denied.length) {
101
+ return $t(
102
+ "duplicateNoPermission",
103
+ "You do not have permission to duplicate this block."
104
+ );
105
+ }
93
106
  if (!field.allowedBundles.length || bundles.some((bundle) => !field.allowedBundles.includes(bundle))) {
94
- return false;
107
+ return $t(
108
+ "duplicateNotAllowed",
109
+ "This block type is not allowed in this field."
110
+ );
95
111
  }
96
112
  }
97
- return true;
113
+ return false;
98
114
  });
99
115
  </script>
100
116
 
@@ -3,7 +3,7 @@
3
3
  id="edit"
4
4
  edit-only
5
5
  :title="$t('edit', 'Edit...')"
6
- :disabled="!canEdit"
6
+ :disabled="editDisabledReason"
7
7
  meta
8
8
  key-code="E"
9
9
  icon="bk_mdi_edit"
@@ -35,13 +35,13 @@ function isFragment(item) {
35
35
  function isFeatureFragment(item) {
36
36
  return !!item.fragment?.name && featureFragmentNames.includes(item.fragment.name);
37
37
  }
38
- const canEdit = computed(() => {
38
+ const editDisabledReason = computed(() => {
39
39
  const item = selection.item.value;
40
40
  if (!item) {
41
41
  return false;
42
42
  }
43
43
  if (isFragment(item)) {
44
- return isFeatureFragment(item);
44
+ return isFeatureFragment(item) ? false : $t("editFragmentNotEditable", "This fragment cannot be edited.");
45
45
  }
46
46
  const definition = definitions.getBlockDefinition(
47
47
  item.bundle,
@@ -49,21 +49,42 @@ const canEdit = computed(() => {
49
49
  item.parentBlockBundle
50
50
  );
51
51
  if (definition?.editor?.disableEdit) {
52
- return false;
52
+ return $t(
53
+ "editDisabledByDefinition",
54
+ "Editing is disabled for this block type."
55
+ );
56
+ }
57
+ if (!permissions.checkBlockBundlePermission(item.bundle, "edit")) {
58
+ return $t(
59
+ "editNoPermission",
60
+ "You do not have permission to edit this block."
61
+ );
53
62
  }
54
63
  if (item.library?.libraryItemUuid) {
55
64
  if (!userCanEditLibraryItems.value) {
56
- return false;
65
+ return $t(
66
+ "editNoLibraryPermission",
67
+ "You do not have permission to edit library items."
68
+ );
69
+ }
70
+ if (!adapter.getLibraryItemEditUrl || state.editMode.value !== "editing" && state.editMode.value !== "translating" || item.isNew) {
71
+ return $t(
72
+ "editLibraryNotAvailable",
73
+ "This reusable block cannot be edited right now."
74
+ );
57
75
  }
58
- return !!adapter.getLibraryItemEditUrl && (state.editMode.value === "editing" || state.editMode.value === "translating") && !item.isNew;
76
+ return false;
77
+ }
78
+ if (state.editMode.value !== "editing") {
79
+ return false;
59
80
  }
60
- return state.editMode.value === "editing";
81
+ return false;
61
82
  });
62
83
  function onClick(items) {
63
84
  if (items.length !== 1) {
64
85
  return;
65
86
  }
66
- if (!canEdit.value) {
87
+ if (editDisabledReason.value) {
67
88
  return;
68
89
  }
69
90
  const item = items[0];
@@ -31,7 +31,18 @@ defineBlokkliFeature({
31
31
  requiredAdapterMethods: ["updateFieldValue", "getEditableFieldConfig"],
32
32
  description: "Implements a form overlay to edit a single field of a block."
33
33
  });
34
- const { selection, adapter, types, $t, state, directive, blocks, context, ui } = useBlokkli();
34
+ const {
35
+ selection,
36
+ adapter,
37
+ types,
38
+ $t,
39
+ state,
40
+ directive,
41
+ blocks,
42
+ context,
43
+ ui,
44
+ permissions
45
+ } = useBlokkli();
35
46
  const selectedEditable = ref(null);
36
47
  const hasTransition = ref(false);
37
48
  const key = computed(() => {
@@ -65,6 +76,9 @@ const buildEditable = (fieldName, uuid) => {
65
76
  if (host.bundle === fromLibraryBlockBundle) {
66
77
  return;
67
78
  }
79
+ if (host.type === itemEntityType && (!permissions.checkBlockBundlePermission(host.bundle, "edit") || permissions.blockHasRestrictedAncestor(host.uuid))) {
80
+ return;
81
+ }
68
82
  const config = types.editableFieldConfig.forName(
69
83
  host.type,
70
84
  host.bundle,
@@ -25,7 +25,10 @@ const { adapter } = defineBlokkliFeature({
25
25
  requiredAdapterMethods: ["fragmentsAddBlock"],
26
26
  dependencies: ["add-list"]
27
27
  });
28
- const { state, $t, types, dom, ui } = useBlokkli();
28
+ const { state, $t, types, dom, ui, permissions } = useBlokkli();
29
+ const canAddFragment = computed(
30
+ () => permissions.checkBlockBundlePermission(fragmentBlockBundle, "add")
31
+ );
29
32
  const placedAction = ref(null);
30
33
  const onAddFragment = async (name) => {
31
34
  if (!placedAction.value || !adapter.fragmentsAddBlock) {
@@ -44,7 +47,7 @@ const isSupportedOnEntity = computed(
44
47
  () => types.generallyAvailableBundles.find((v) => v.id === fragmentBlockBundle)
45
48
  );
46
49
  defineAddAction(() => {
47
- if (!isSupportedOnEntity.value) {
50
+ if (!isSupportedOnEntity.value || !canAddFragment.value) {
48
51
  return;
49
52
  }
50
53
  return {
@@ -24,7 +24,8 @@ const {
24
24
  ui,
25
25
  directive,
26
26
  blocks,
27
- fields
27
+ fields,
28
+ permissions
28
29
  } = useBlokkli();
29
30
  const MAX_RECTS = 11;
30
31
  function getDeepestUuid(uuids) {
@@ -120,7 +121,9 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
120
121
  height: rect.height / scale
121
122
  };
122
123
  if (isInsideRect(artboardMouseX, artboardMouseY, blockRect)) {
123
- hoveredUuids.push(uuid);
124
+ if (!permissions.blockHasRestrictedAncestor(uuid)) {
125
+ hoveredUuids.push(uuid);
126
+ }
124
127
  }
125
128
  }
126
129
  const deepestUuid = getDeepestUuid(hoveredUuids);
@@ -139,6 +142,10 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
139
142
  if (!isInsideRect(artboardMouseX, artboardMouseY, editableRect)) continue;
140
143
  const key = editableRect.key;
141
144
  const entityUuid = key.split(":")[2];
145
+ const block = blocks.getBlock(entityUuid);
146
+ if (block && (!permissions.checkBlockBundlePermission(block.bundle, "edit") || permissions.blockHasRestrictedAncestor(entityUuid))) {
147
+ continue;
148
+ }
142
149
  if (deepestUuid && entityUuid === deepestUuid) {
143
150
  hoveredEditableFieldRect = editableRect;
144
151
  break;
@@ -187,8 +194,10 @@ function updateHoverState(mouseX, mouseY, offset, scale, artboardSize) {
187
194
  hoverState.radii[level * 4 + 3] = style.radius[3];
188
195
  let type = 0;
189
196
  if (isDeepest) {
190
- const isFromLibrary = state.fromLibraryUuids.value.includes(uuid);
191
- if (isFromLibrary) {
197
+ const isRestricted = !permissions.checkBlockBundlePermission(block.bundle, "edit") || !permissions.checkBlockBundlePermission(block.bundle, "delete") || !permissions.checkBlockBundlePermission(block.bundle, "add");
198
+ if (isRestricted) {
199
+ type = 5;
200
+ } else if (state.fromLibraryUuids.value.includes(uuid)) {
192
201
  type = 4;
193
202
  } else {
194
203
  type = style.isInverted ? 3 : 1;
@@ -223,7 +232,8 @@ const uniforms = computed(() => {
223
232
  u_color_accent: theme.accent.value[600],
224
233
  u_color_teal: theme.teal.value.normal,
225
234
  u_color_white: [255, 255, 255],
226
- u_color_lime: theme.lime.value.normal
235
+ u_color_lime: theme.lime.value.normal,
236
+ u_color_yellow: theme.yellow.value.normal
227
237
  };
228
238
  });
229
239
  onBlokkliEvent("state:reloaded", () => {
@@ -279,6 +289,7 @@ const { collector } = defineRenderer("hover-overlay", {
279
289
  u_color_teal: toShaderColor(uniforms.value.u_color_teal),
280
290
  u_color_white: toShaderColor(uniforms.value.u_color_white),
281
291
  u_color_lime: toShaderColor(uniforms.value.u_color_lime),
292
+ u_color_yellow: toShaderColor(uniforms.value.u_color_yellow),
282
293
  u_hover_positions: hoverState.positions,
283
294
  u_hover_radii: hoverState.radii,
284
295
  u_hover_types: hoverState.types,
@@ -392,7 +403,9 @@ const { collector } = defineRenderer("hover-overlay", {
392
403
  ctx2d.stroke();
393
404
  } else {
394
405
  let strokeColor = colors.u_color_mono;
395
- if (type === 4) {
406
+ if (type === 5) {
407
+ strokeColor = colors.u_color_yellow;
408
+ } else if (type === 4) {
396
409
  strokeColor = colors.u_color_lime;
397
410
  } else if (type === 3) {
398
411
  strokeColor = colors.u_color_white;