@blokkli/editor 2.0.0-alpha.16 → 2.0.0-alpha.17

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 (106) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +265 -83
  3. package/dist/modules/drupal/graphql/base/fragment.blokkliProps.graphql +1 -1
  4. package/dist/modules/drupal/graphql/features/comments.graphql +11 -8
  5. package/dist/modules/drupal/runtime/adapter/index.js +2 -2
  6. package/dist/runtime/blokkliPlugins/ItemAction/index.vue +1 -3
  7. package/dist/runtime/components/Blocks/FromLibrary/index.vue +4 -2
  8. package/dist/runtime/components/BlokkliEditable.vue +22 -4
  9. package/dist/runtime/components/BlokkliProvider.vue +29 -20
  10. package/dist/runtime/components/BlokkliProvider.vue.d.ts +2 -1
  11. package/dist/runtime/components/Edit/Actions/index.vue +9 -4
  12. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +420 -25
  13. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +80 -0
  14. package/dist/runtime/components/Edit/ArtboardTooltip/index.vue.d.ts +32 -0
  15. package/dist/runtime/components/Edit/Banner/index.vue +51 -0
  16. package/dist/runtime/components/Edit/Banner/index.vue.d.ts +18 -0
  17. package/dist/runtime/components/Edit/EditIndicator.vue +118 -44
  18. package/dist/runtime/components/Edit/EditIndicator.vue.d.ts +3 -0
  19. package/dist/runtime/components/Edit/EditProvider.vue +79 -22
  20. package/dist/runtime/components/Edit/EditProvider.vue.d.ts +2 -0
  21. package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +19 -20
  22. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +1 -1
  23. package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +2 -0
  24. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue +35 -20
  25. package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue.d.ts +5 -3
  26. package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue +29 -0
  27. package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue.d.ts +13 -0
  28. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue +22 -16
  29. package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue.d.ts +1 -0
  30. package/dist/runtime/components/Edit/Features/Comments/Overlay/index.vue +15 -6
  31. package/dist/runtime/components/Edit/Features/Comments/index.vue +20 -8
  32. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +26 -35
  33. package/dist/runtime/components/Edit/Features/Debug/Renderer.vue +240 -0
  34. package/dist/runtime/components/Edit/Features/Debug/Renderer.vue.d.ts +6 -0
  35. package/dist/runtime/components/Edit/Features/Debug/index.vue +4 -165
  36. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +1 -1
  37. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +41 -37
  38. package/dist/runtime/components/Edit/Features/Edit/index.vue +1 -1
  39. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +63 -3
  40. package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue +13 -9
  41. package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +17 -76
  42. package/dist/runtime/components/Edit/Features/EditableField/index.vue +1 -1
  43. package/dist/runtime/components/Edit/Features/History/index.vue +5 -2
  44. package/dist/runtime/components/Edit/Features/Hover/Overlay/fragment.glsl +139 -0
  45. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue +270 -0
  46. package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue.d.ts +6 -0
  47. package/dist/runtime/components/Edit/Features/Hover/Overlay/vertex.glsl +117 -0
  48. package/dist/runtime/components/Edit/Features/Hover/index.vue +25 -0
  49. package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue +19 -27
  50. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +27 -23
  51. package/dist/runtime/components/Edit/Features/Library/index.vue +2 -1
  52. package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +34 -27
  53. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +2 -4
  54. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +6 -1
  55. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +1 -0
  56. package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue +35 -0
  57. package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue.d.ts +6 -0
  58. package/dist/runtime/components/Edit/Features/Ownership/index.vue +7 -25
  59. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +5 -1
  60. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue +39 -74
  61. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +4 -2
  62. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/fragment.glsl +106 -0
  63. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +417 -0
  64. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue.d.ts +32 -0
  65. package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/vertex.glsl +102 -0
  66. package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +33 -106
  67. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +88 -29
  68. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +2 -0
  69. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +11 -2
  70. package/dist/runtime/components/Edit/Features/Selection/index.vue +5 -12
  71. package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue +17 -11
  72. package/dist/runtime/components/Edit/Features/Translations/index.vue +13 -16
  73. package/dist/runtime/components/Edit/Form/Text/index.vue +2 -1
  74. package/dist/runtime/components/Edit/Form/Text/index.vue.d.ts +1 -0
  75. package/dist/runtime/components/Edit/Indicators/index.vue +1 -1
  76. package/dist/runtime/components/Edit/Konami/Game/index.vue +5 -5
  77. package/dist/runtime/components/Edit/index.d.ts +5 -3
  78. package/dist/runtime/components/Edit/index.js +8 -4
  79. package/dist/runtime/composables/defineBlokkli.js +4 -2
  80. package/dist/runtime/css/output.css +1 -1
  81. package/dist/runtime/helpers/animationProvider.d.ts +34 -1
  82. package/dist/runtime/helpers/animationProvider.js +175 -48
  83. package/dist/runtime/helpers/composables/defineRenderer.d.ts +8 -0
  84. package/dist/runtime/helpers/composables/defineRenderer.js +8 -0
  85. package/dist/runtime/helpers/composables/useStickyToolbar.d.ts +4 -1
  86. package/dist/runtime/helpers/composables/useStickyToolbar.js +53 -35
  87. package/dist/runtime/helpers/dom/index.d.ts +1 -0
  88. package/dist/runtime/helpers/domProvider.d.ts +46 -0
  89. package/dist/runtime/helpers/domProvider.js +95 -6
  90. package/dist/runtime/helpers/editableProvider.d.ts +14 -0
  91. package/dist/runtime/helpers/editableProvider.js +144 -0
  92. package/dist/runtime/helpers/stateProvider.d.ts +6 -2
  93. package/dist/runtime/helpers/stateProvider.js +66 -3
  94. package/dist/runtime/helpers/storageProvider.d.ts +3 -2
  95. package/dist/runtime/helpers/storageProvider.js +6 -2
  96. package/dist/runtime/helpers/symbols.d.ts +1 -0
  97. package/dist/runtime/helpers/symbols.js +1 -0
  98. package/dist/runtime/helpers/uiProvider.d.ts +8 -1
  99. package/dist/runtime/helpers/uiProvider.js +34 -2
  100. package/dist/runtime/plugins/blokkliEditable.js +74 -3
  101. package/dist/runtime/types/index.d.ts +13 -1
  102. package/package.json +1 -1
  103. package/dist/runtime/components/Edit/DragInteractions/index.vue +0 -401
  104. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue +0 -54
  105. package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue.d.ts +0 -14
  106. /package/dist/runtime/components/Edit/{DragInteractions → Features/Hover}/index.vue.d.ts +0 -0
@@ -1,21 +1,19 @@
1
1
  <template>
2
2
  <Teleport to="body">
3
- <div v-show="isVisible" class="bk">
4
- <div class="bk-edit-indicator" :style="style">
5
- <button
6
- ref="button"
7
- class="bk-button bk-is-primary"
8
- @mouseenter="isHovering = true"
9
- @mouseleave="isHovering = false"
10
- @click="$emit('edit')"
11
- >
12
- {{ label }}
13
- </button>
14
- </div>
3
+ <div class="bk">
4
+ <button
5
+ ref="button"
6
+ class="bk-edit-indicator bk-button bk-is-primary"
7
+ @mouseenter="isHovering = true"
8
+ @mouseleave="isHovering = false"
9
+ @click="$emit('edit')"
10
+ >
11
+ {{ label }}
12
+ </button>
15
13
 
16
14
  <div
17
- v-if="overlayStyle"
18
- :style="overlayStyle"
15
+ v-show="isHovering"
16
+ ref="overlay"
19
17
  class="bk-edit-indicator-overlay"
20
18
  />
21
19
  </div>
@@ -24,47 +22,123 @@
24
22
 
25
23
  <script setup>
26
24
  import textProvider from "#blokkli/helpers/textProvider";
27
- import { ref, computed } from "#imports";
25
+ import { ref, onMounted, onBeforeUnmount, useState, computed } from "#imports";
28
26
  import "#blokkli-build/styles.css";
29
27
  import useAnimationFrame from "#blokkli/helpers/composables/useAnimationFrame";
30
28
  const props = defineProps({
31
29
  uuid: { type: String, required: true },
32
- editLabel: { type: String, required: false }
30
+ entityType: { type: String, required: true },
31
+ editLabel: { type: String, required: false },
32
+ permissions: { type: Array, required: true }
33
33
  });
34
+ const key = computed(() => props.entityType + ":" + props.uuid);
34
35
  const $t = textProvider();
35
- const label = computed(
36
- () => props.editLabel || $t("editIndicatorLabel", "Edit blocks")
37
- );
36
+ const label = computed(() => {
37
+ if (props.editLabel) {
38
+ return props.editLabel;
39
+ } else if (props.permissions.includes("edit")) {
40
+ return $t("editIndicatorLabel", "Edit blocks");
41
+ } else if (props.permissions.includes("review")) {
42
+ return $t("editIndicatorLabelReview", "Review changes");
43
+ } else if (props.permissions.includes("view")) {
44
+ return $t("editIndicatorLabelView", "View changes");
45
+ }
46
+ return null;
47
+ });
38
48
  defineEmits(["edit"]);
39
49
  const isHovering = ref(false);
40
- const style = ref({});
41
50
  const button = ref(null);
42
- const isVisible = ref(false);
43
- const overlayStyle = ref(null);
44
- function calculateIdealYPosition(elementHeight, bounds) {
45
- const idealTop = Math.min(
46
- Math.max(bounds.top, bounds.bottom - elementHeight - 20),
47
- 20
48
- );
49
- return Math.max(idealTop, bounds.y + 20);
51
+ const overlay = ref(null);
52
+ const targetElement = ref(null);
53
+ const indicatorRegistry = useState(
54
+ "blokkliEditIndicators",
55
+ () => []
56
+ );
57
+ const isManager = computed(() => {
58
+ return indicatorRegistry.value[0]?.key === key.value;
59
+ });
60
+ function calculateIdealYPosition(buttonHeight, bounds, gap) {
61
+ const elementHeight = bounds.bottom - bounds.top;
62
+ let position;
63
+ if (elementHeight < 100) {
64
+ position = bounds.top + elementHeight / 2 - buttonHeight / 2;
65
+ } else {
66
+ position = bounds.top + gap;
67
+ }
68
+ position = Math.max(position, gap);
69
+ return Math.min(position, bounds.bottom - buttonHeight - gap);
50
70
  }
51
- useAnimationFrame(() => {
52
- const el = document.querySelector(`[data-provider-uuid="${props.uuid}"]`);
53
- isVisible.value = window.innerWidth > 1024;
54
- if (isVisible.value && el && el instanceof HTMLElement && button.value) {
55
- const rect = el.getBoundingClientRect();
56
- const buttonHeight = button.value.getBoundingClientRect().height;
57
- const y = calculateIdealYPosition(buttonHeight, rect);
58
- style.value.transform = `translateY(${y}px)`;
59
- if (isHovering.value) {
60
- overlayStyle.value = {
61
- width: rect.width + "px",
62
- height: rect.height + "px",
63
- transform: `translate(${rect.x}px, ${rect.y}px)`
64
- };
65
- } else {
66
- overlayStyle.value = null;
71
+ const GAP = 15;
72
+ const indicators = computed(() => {
73
+ const indicators2 = [...indicatorRegistry.value];
74
+ return indicators2.sort((a, b) => {
75
+ const position = a.targetElement.compareDocumentPosition(b.targetElement);
76
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) {
77
+ return -1;
78
+ }
79
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) {
80
+ return 1;
81
+ }
82
+ return 0;
83
+ });
84
+ });
85
+ function updateAllIndicatorPositions() {
86
+ const positions = [];
87
+ const heights = [];
88
+ for (let i = 0; i < indicators.value.length; i++) {
89
+ const data = indicators.value[i];
90
+ const rect = data.targetElement.getBoundingClientRect();
91
+ const buttonHeight = data.buttonElement.offsetHeight;
92
+ let idealY = calculateIdealYPosition(buttonHeight, rect, GAP);
93
+ for (let j = 0; j < i; j++) {
94
+ const prevRect = indicators.value[j].targetElement.getBoundingClientRect();
95
+ const prevElementTop = prevRect.top;
96
+ const prevElementHeight = prevRect.height;
97
+ const collisionPosition = prevElementTop + prevElementHeight + GAP;
98
+ if (idealY < collisionPosition) {
99
+ idealY = collisionPosition;
100
+ }
67
101
  }
102
+ const elementBottom = rect.bottom - buttonHeight - GAP;
103
+ if (elementBottom < idealY) {
104
+ idealY = elementBottom;
105
+ }
106
+ idealY = Math.round(idealY);
107
+ positions.push(idealY);
108
+ heights.push(buttonHeight);
109
+ data.buttonElement.style.transform = `translateY(${idealY}px)`;
110
+ }
111
+ }
112
+ onMounted(() => {
113
+ const el = document.querySelector(`[data-provider-uuid="${props.uuid}"]`);
114
+ if (el && el instanceof HTMLElement) {
115
+ targetElement.value = el;
116
+ }
117
+ if (button.value && targetElement.value) {
118
+ indicatorRegistry.value.push({
119
+ key: key.value,
120
+ targetElement: targetElement.value,
121
+ buttonElement: button.value
122
+ });
123
+ }
124
+ });
125
+ onBeforeUnmount(() => {
126
+ indicatorRegistry.value = indicatorRegistry.value.filter(
127
+ (i) => i.key !== key.value
128
+ );
129
+ });
130
+ useAnimationFrame(() => {
131
+ if (!button.value || !targetElement.value) {
132
+ return;
133
+ }
134
+ if (isManager.value) {
135
+ updateAllIndicatorPositions();
136
+ }
137
+ if (isHovering.value && overlay.value) {
138
+ const rect = targetElement.value.getBoundingClientRect();
139
+ overlay.value.style.width = rect.width + "px";
140
+ overlay.value.style.height = rect.height + "px";
141
+ overlay.value.style.transform = `translate(${rect.x}px, ${rect.y}px)`;
68
142
  }
69
143
  });
70
144
  </script>
@@ -1,7 +1,10 @@
1
1
  import '#blokkli-build/styles.css';
2
+ import type { EditPermission } from '#blokkli/types';
2
3
  type __VLS_Props = {
3
4
  uuid: string;
5
+ entityType: string;
4
6
  editLabel?: string;
7
+ permissions: EditPermission[];
5
8
  };
6
9
  declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
7
10
  edit: (...args: any[]) => void;
@@ -8,24 +8,28 @@
8
8
  </Transition>
9
9
 
10
10
  <div id="bk-banner-container">
11
- <Messages />
12
- <div v-if="!state.stateAvailable.value" class="bk-state-unavailable">
13
- <h2>
14
- {{
15
- $t("stateUnavailableTitle", "The edit state could not be loaded.")
16
- }}
17
- </h2>
18
- <p>
19
- {{
20
- $t(
21
- "stateUnavailableText",
22
- "This could be due to missing permissions or a temporary problem. Please try again later."
23
- )
24
- }}
25
- </p>
11
+ <div id="bk-banner-list" class="bk">
12
+ <Banner
13
+ v-if="!state.stateAvailable.value"
14
+ id="state-unavailable"
15
+ icon="sad"
16
+ scheme="red"
17
+ :text="stateNotAvailableText"
18
+ />
19
+ <Banner
20
+ v-if="viewOnlyBanner"
21
+ id="view-only"
22
+ :icon="viewOnlyBanner.icon"
23
+ scheme="yellow"
24
+ :text="viewOnlyBanner.text"
25
+ />
26
26
  </div>
27
+ <Messages />
27
28
  </div>
28
29
  </Teleport>
30
+ <Teleport to="#nuxt-root">
31
+ <div id="bk-canvas-overlay" class="bk bk-canvas-overlay" />
32
+ </Teleport>
29
33
  <Actions v-if="!isInitializing" />
30
34
  <Toolbar @loaded="toolbarLoaded = true" />
31
35
  <AppMenu v-if="toolbarLoaded" />
@@ -35,7 +39,6 @@
35
39
  :key="route.fullPath"
36
40
  @loaded="featuresLoaded = true"
37
41
  />
38
- <DragInteractions v-if="!isInitializing" />
39
42
  <AnimationCanvas v-if="!isInitializing" />
40
43
  <Konami />
41
44
  <SystemRequirements />
@@ -66,10 +69,10 @@ import Features from "./Features/index.vue";
66
69
  import Indicators from "./Indicators/index.vue";
67
70
  import AppMenu from "./AppMenu/index.vue";
68
71
  import DraggableList from "./DraggableList.vue";
69
- import DragInteractions from "./DragInteractions/index.vue";
70
72
  import AnimationCanvas from "./AnimationCanvas/index.vue";
71
73
  import SystemRequirements from "./SystemRequirements/index.vue";
72
74
  import Konami from "./Konami/index.vue";
75
+ import Banner from "./Banner/index.vue";
73
76
  import animationProvider from "./../../helpers/animationProvider";
74
77
  import keyboardProvider from "./../../helpers/keyboardProvider";
75
78
  import selectionProvider from "./../../helpers/selectionProvider";
@@ -89,6 +92,7 @@ import definitionProvider from "./../../helpers/definitionProvider";
89
92
  import dropAreasProvider from "./../../helpers/dropAreaProvider";
90
93
  import indicatorsProvider from "./../../helpers/indicatorsProvider";
91
94
  import pluginProvider from "./../../helpers/pluginProvider";
95
+ import editableProvider from "./../../helpers/editableProvider";
92
96
  import { eventBus } from "#blokkli/helpers/eventBus";
93
97
  import "#blokkli-build/styles.css";
94
98
  import getAdapter from "#blokkli-build/edit-adapter";
@@ -109,7 +113,8 @@ const props = defineProps({
109
113
  entityUuid: { type: String, required: true },
110
114
  entityBundle: { type: String, required: true },
111
115
  language: { type: String, required: false, default: "en" },
112
- isolate: { type: Boolean, required: false }
116
+ isolate: { type: Boolean, required: false },
117
+ permissions: { type: Array, required: true }
113
118
  });
114
119
  defineSlots();
115
120
  const context = computed(() => {
@@ -129,8 +134,14 @@ const featuresLoaded = ref(false);
129
134
  const isInitializing = ref(true);
130
135
  const definitions = definitionProvider();
131
136
  const $t = textProvider(context);
132
- const state = await editStateProvider(adapter, context, $t, providerKey);
133
- const storage = await storageProvider(adapter);
137
+ const state = await editStateProvider(
138
+ adapter,
139
+ context,
140
+ $t,
141
+ providerKey,
142
+ props.permissions
143
+ );
144
+ const storage = await storageProvider(adapter, context);
134
145
  const debug = debugProvider(storage);
135
146
  const features = featuresProvider(storage);
136
147
  const theme = themeProvider();
@@ -140,12 +151,13 @@ const dropAreas = dropAreasProvider();
140
151
  const broadcast = broadcastProvider();
141
152
  const ui = uiProvider(storage, state, context);
142
153
  const dom = domProvider(ui, debug, definitions);
143
- const animation = animationProvider(ui, storage);
144
- const keyboard = keyboardProvider(animation);
145
154
  const selection = selectionProvider(dom);
155
+ const animation = animationProvider(ui, storage, selection);
156
+ const keyboard = keyboardProvider(animation);
146
157
  const types = await typesProvider(adapter, selection, context);
147
158
  const indicators = indicatorsProvider();
148
159
  const plugins = pluginProvider();
160
+ const editable = editableProvider(ui);
149
161
  const mutatedEntity = computed(() => state.mutatedEntity.value || props.entity);
150
162
  const onContextMenu = (e) => {
151
163
  e.preventDefault();
@@ -177,6 +189,7 @@ onMounted(() => {
177
189
  document.documentElement.addEventListener("touchstart", onTouchStart);
178
190
  baseLogger.log("EditProvider mounted");
179
191
  dom.init();
192
+ editable.init();
180
193
  isInitializing.value = false;
181
194
  broadcast.emit("editorLoaded", { uuid: props.entityUuid });
182
195
  });
@@ -209,6 +222,7 @@ provide(INJECT_APP, {
209
222
  dom,
210
223
  dropAreas,
211
224
  eventBus,
225
+ editable,
212
226
  features,
213
227
  indicators,
214
228
  keyboard,
@@ -222,6 +236,49 @@ provide(INJECT_APP, {
222
236
  types,
223
237
  ui
224
238
  });
239
+ function textWithHighlight(title, text) {
240
+ return `<strong>${title}</strong> ${text}`;
241
+ }
242
+ const stateNotAvailableText = computed(() => {
243
+ return textWithHighlight(
244
+ $t("stateUnavailableTitle", "The edit state could not be loaded."),
245
+ $t(
246
+ "stateUnavailableText",
247
+ "This could be due to missing permissions or a temporary problem. Please try again later."
248
+ )
249
+ );
250
+ });
251
+ const viewOnlyBanner = computed(
252
+ () => {
253
+ if (props.permissions.includes("edit")) {
254
+ return null;
255
+ }
256
+ if (props.permissions.includes("review")) {
257
+ return {
258
+ text: textWithHighlight(
259
+ $t("viewBannerReviewTitle", "You are in review mode."),
260
+ $t(
261
+ "viewBannerReviewText",
262
+ "You can view and add comments but cannot edit content."
263
+ )
264
+ ),
265
+ icon: "comment"
266
+ };
267
+ } else if (props.permissions.includes("view")) {
268
+ return {
269
+ text: textWithHighlight(
270
+ $t("viewBannerViewTitle", "You are in view-only mode."),
271
+ $t(
272
+ "viewBannerViewText",
273
+ "You can view comments but cannot edit content."
274
+ )
275
+ ),
276
+ icon: "eye"
277
+ };
278
+ }
279
+ return null;
280
+ }
281
+ );
225
282
  const isProxyMode = computed(() => ui.isProxyMode.value);
226
283
  provide(INJECT_GLOBAL_PROXY_MODE, isProxyMode);
227
284
  if (import.meta.hot) {
@@ -1,3 +1,4 @@
1
+ import type { EditPermission } from '#blokkli/types';
1
2
  import '#blokkli-build/styles.css';
2
3
  declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
3
4
  props: __VLS_PrettifyLocal<Pick<Partial<{}> & Omit<{} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, never>, never> & {
@@ -7,6 +8,7 @@ declare const _default: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>
7
8
  entityBundle: string;
8
9
  language?: string;
9
10
  isolate?: boolean;
11
+ permissions: EditPermission[];
10
12
  } & Partial<{}>> & import("vue").PublicProps;
11
13
  expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
12
14
  attrs: any;
@@ -4,7 +4,8 @@
4
4
 
5
5
  <script setup>
6
6
  import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
7
- import { useBlokkli, onBeforeUnmount, computed } from "#imports";
7
+ import defineRenderer from "#blokkli/helpers/composables/defineRenderer";
8
+ import { useBlokkli, computed } from "#imports";
8
9
  import {
9
10
  setBuffersAndAttributes,
10
11
  drawBufferInfo,
@@ -112,23 +113,24 @@ class AnalyzeRectangleBufferCollector extends RectangleBufferCollector {
112
113
  }
113
114
  }
114
115
  const collector = new AnalyzeRectangleBufferCollector(props.gl);
115
- onBlokkliEvent("canvas:draw", () => {
116
- if (selection.isMultiSelecting.value || selection.isDragging.value) {
117
- return;
118
- }
119
- props.gl.useProgram(programInfo.program);
120
- const { info } = collector.getBufferInfo();
121
- if (!info) {
122
- return;
116
+ defineRenderer("analyze-overlay", {
117
+ zIndex: 500,
118
+ enabled: () => !selection.isMultiSelecting.value && !selection.isDragging.value,
119
+ render: (ctx) => {
120
+ ctx.gl.useProgram(programInfo.program);
121
+ const { info } = collector.getBufferInfo();
122
+ if (!info) {
123
+ return;
124
+ }
125
+ setUniforms(programInfo, {
126
+ u_color_violation: toShaderColor(theme.red.value.normal),
127
+ u_color_incomplete: toShaderColor(theme.yellow.value.normal),
128
+ u_color_pass: toShaderColor(theme.lime.value.normal)
129
+ });
130
+ animation.setSharedUniforms(ctx.gl, programInfo);
131
+ setBuffersAndAttributes(ctx.gl, programInfo, info);
132
+ drawBufferInfo(ctx.gl, info, ctx.gl.TRIANGLES);
123
133
  }
124
- setUniforms(programInfo, {
125
- u_color_violation: toShaderColor(theme.red.value.normal),
126
- u_color_incomplete: toShaderColor(theme.yellow.value.normal),
127
- u_color_pass: toShaderColor(theme.lime.value.normal)
128
- });
129
- animation.setSharedUniforms(props.gl, programInfo);
130
- setBuffersAndAttributes(props.gl, programInfo, info);
131
- drawBufferInfo(props.gl, info, props.gl.TRIANGLES);
132
134
  });
133
135
  onBlokkliEvent("ui:resized", function() {
134
136
  collector.clearCache();
@@ -156,9 +158,6 @@ onBlokkliEvent("mouse:up", (e) => {
156
158
  }
157
159
  }
158
160
  });
159
- onBeforeUnmount(() => {
160
- props.gl.clear(props.gl.COLOR_BUFFER_BIT);
161
- });
162
161
  </script>
163
162
 
164
163
  <script>
@@ -36,7 +36,7 @@
36
36
  :key="renderKey"
37
37
  to="#blokkli-add-list-sidebar-before"
38
38
  >
39
- <div class="bk-list-sidebar-form">
39
+ <div class="bk bk-list-sidebar-form">
40
40
  <input
41
41
  id="add_block_search"
42
42
  v-model="searchText"
@@ -28,6 +28,7 @@ import { useBlokkli, defineBlokkliFeature, ref, computed } from "#imports";
28
28
  import { PluginToolbarButton } from "#blokkli/plugins";
29
29
  import { BlokkliTransition } from "#blokkli/components";
30
30
  import Palette from "./Palette/index.vue";
31
+ import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
31
32
  defineBlokkliFeature({
32
33
  id: "command-palette",
33
34
  icon: "command",
@@ -38,6 +39,7 @@ defineBlokkliFeature({
38
39
  const { $t } = useBlokkli();
39
40
  const isVisible = ref(false);
40
41
  const label = computed(() => $t("commandPaletteOpen", "Open Command Palette"));
42
+ onBlokkliEvent("window:clickAway", () => isVisible.value = false);
41
43
  </script>
42
44
 
43
45
  <script>
@@ -1,29 +1,44 @@
1
1
  <template>
2
- <div class="bk-blokkli-item-actions-comment-dropdown" @keydown.capture.stop>
3
- <label for="comment_body" class="bk-form-label">{{
4
- $t("commentBody", "Comment")
5
- }}</label>
6
- <textarea
7
- id="comment_body"
8
- v-model="comment"
9
- type="text"
10
- class="bk-form-input"
11
- rows="5"
12
- required
13
- />
14
- <button class="bk-button bk-is-primary" @click="$emit('add', comment)">
15
- {{ $t("commentSave", "Submit comment") }}
16
- </button>
17
- </div>
2
+ <ArtboardTooltip
3
+ id="add-comment"
4
+ :title="$t('addCommentHeader', 'Add Comment')"
5
+ class="bk-add-comment"
6
+ @close="$emit('close')"
7
+ >
8
+ <div class="bk-add-comment-inner" @keydown.capture.stop>
9
+ <CommentInput id="comment_body" v-model="comment" />
10
+ <footer>
11
+ <button
12
+ :disabled="!comment"
13
+ class="bk-button bk-is-warning"
14
+ @click.prevent="onAdd"
15
+ >
16
+ {{ $t("commentSave", "Submit comment") }}
17
+ </button>
18
+ </footer>
19
+ </div>
20
+ </ArtboardTooltip>
18
21
  </template>
19
22
 
20
23
  <script setup>
21
- import { ref, useBlokkli } from "#imports";
22
- const comment = ref("");
23
- defineEmits(["add"]);
24
- const { $t } = useBlokkli();
24
+ import { onBeforeUnmount, onMounted, useBlokkli } from "#imports";
25
+ import { ArtboardTooltip } from "#blokkli/components";
26
+ import CommentInput from "./../CommentInput/index.vue";
27
+ const emit = defineEmits(["add", "close"]);
28
+ const { $t, ui, storage } = useBlokkli();
29
+ const comment = storage.useWithContextPrefix("commentAddText", "");
25
30
  const getComment = () => {
26
31
  return comment.value;
27
32
  };
33
+ function onAdd() {
34
+ emit("add", comment.value);
35
+ comment.value = "";
36
+ }
28
37
  defineExpose({ getComment });
38
+ onMounted(() => {
39
+ ui.setSelectionColor("add-comment", "yellow");
40
+ });
41
+ onBeforeUnmount(() => {
42
+ ui.removeSelectionColor("add-comment");
43
+ });
29
44
  </script>
@@ -1,8 +1,10 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
2
  getComment: () => string;
3
- }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
4
- add: (...args: any[]) => void;
3
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
4
+ close: () => any;
5
+ add: (comment: string) => any;
5
6
  }, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
6
- onAdd?: ((...args: any[]) => any) | undefined;
7
+ onClose?: (() => any) | undefined;
8
+ onAdd?: ((comment: string) => any) | undefined;
7
9
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
8
10
  export default _default;
@@ -0,0 +1,29 @@
1
+ <template>
2
+ <div class="bk-comment-textarea">
3
+ <textarea
4
+ id="comment_body"
5
+ ref="textarea"
6
+ v-model="value"
7
+ type="text"
8
+ class="bk-form-input"
9
+ rows="4"
10
+ :placeholder
11
+ required
12
+ />
13
+ </div>
14
+ </template>
15
+
16
+ <script setup>
17
+ import { onMounted, useTemplateRef } from "#imports";
18
+ defineProps({
19
+ id: { type: String, required: true },
20
+ placeholder: { type: String, required: false }
21
+ });
22
+ const value = defineModel({ type: String });
23
+ const el = useTemplateRef("textarea");
24
+ onMounted(() => {
25
+ if (el.value) {
26
+ el.value.focus();
27
+ }
28
+ });
29
+ </script>
@@ -0,0 +1,13 @@
1
+ type __VLS_Props = {
2
+ id: string;
3
+ placeholder?: string;
4
+ };
5
+ type __VLS_PublicProps = __VLS_Props & {
6
+ modelValue?: string;
7
+ };
8
+ declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
9
+ "update:modelValue": (value: string | undefined) => any;
10
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
11
+ "onUpdate:modelValue"?: ((value: string | undefined) => any) | undefined;
12
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
+ export default _default;