@blokkli/editor 2.0.0-alpha.46 → 2.0.0-alpha.48
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/module.json +1 -1
- package/dist/module.mjs +23 -6
- package/dist/modules/agent/runtime/app/helpers/validation.d.ts +13 -0
- package/dist/modules/agent/runtime/app/helpers/validation.js +22 -0
- package/dist/modules/agent/runtime/app/tools/add_content_search_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_fragment/index.js +12 -1
- package/dist/modules/agent/runtime/app/tools/add_media_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_paragraphs/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/add_reusable_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/add_template/index.js +5 -0
- package/dist/modules/agent/runtime/app/tools/delegate_text_rewrite/index.js +15 -0
- package/dist/modules/agent/runtime/app/tools/delete_paragraphs/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/detach_reusable_paragraph/index.js +12 -0
- package/dist/modules/agent/runtime/app/tools/duplicate_paragraphs/index.js +16 -1
- package/dist/modules/agent/runtime/app/tools/move_paragraphs/index.js +17 -0
- package/dist/modules/agent/runtime/app/tools/rearrange_paragraphs/index.js +11 -0
- package/dist/modules/agent/runtime/app/tools/replace_content_search_item/index.js +8 -0
- package/dist/modules/agent/runtime/app/tools/replace_media_field/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/set_paragraph_options/index.js +10 -0
- package/dist/modules/agent/runtime/app/tools/swap_paragraphs/index.js +15 -0
- package/dist/modules/agent/runtime/app/tools/update_text_fields/index.js +21 -1
- package/dist/modules/agent/runtime/app/types/index.d.ts +6 -6
- package/dist/modules/drupal/index.mjs +2 -1
- package/dist/modules/drupal/runtime/adapter/index.js +15 -3
- package/dist/runtime/editor/components/Actions/index.vue +47 -2
- package/dist/runtime/editor/components/AnimationCanvas/index.vue +6 -3
- package/dist/runtime/editor/components/BundleSelector/index.d.vue.ts +8 -4
- package/dist/runtime/editor/components/BundleSelector/index.vue +111 -13
- package/dist/runtime/editor/components/BundleSelector/index.vue.d.ts +8 -4
- package/dist/runtime/editor/components/EditProvider.vue +2 -2
- package/dist/runtime/editor/components/FlexTextarea/index.vue +8 -1
- package/dist/runtime/editor/css/output.css +1 -1
- package/dist/runtime/editor/features/add-list/Blocks/index.vue +6 -3
- package/dist/runtime/editor/features/analyze/Renderer/index.vue +1 -1
- package/dist/runtime/editor/features/block-scheduler/index.vue +7 -1
- package/dist/runtime/editor/features/changelog/Dialog/index.vue +1 -1
- package/dist/runtime/editor/features/changelog/changelog.json +26 -10
- package/dist/runtime/editor/features/clipboard/index.vue +6 -1
- package/dist/runtime/editor/features/comments/AddForm/index.d.vue.ts +2 -2
- package/dist/runtime/editor/features/comments/AddForm/index.vue.d.ts +2 -2
- package/dist/runtime/editor/features/delete/index.vue +17 -2
- package/dist/runtime/editor/features/dragging-overlay/Renderer/index.vue +12 -2
- package/dist/runtime/editor/features/dragging-overlay/index.vue +5 -2
- package/dist/runtime/editor/features/duplicate/index.vue +23 -7
- package/dist/runtime/editor/features/edit/index.vue +29 -8
- package/dist/runtime/editor/features/editable-field/index.vue +15 -1
- package/dist/runtime/editor/features/fragments/index.vue +5 -2
- package/dist/runtime/editor/features/hover/Renderer/index.vue +19 -6
- package/dist/runtime/editor/features/hover/Renderer/vertex.glsl +5 -2
- package/dist/runtime/editor/features/library/index.vue +52 -8
- package/dist/runtime/editor/features/media-library/Library/FilterSelect/index.d.vue.ts +15 -0
- package/dist/runtime/editor/features/media-library/Library/FilterSelect/index.vue +168 -0
- package/dist/runtime/editor/features/media-library/Library/FilterSelect/index.vue.d.ts +15 -0
- package/dist/runtime/editor/features/media-library/Library/index.vue +21 -16
- package/dist/runtime/editor/features/media-library/index.vue +7 -2
- package/dist/runtime/editor/features/multi-select/Renderer/index.vue +4 -1
- package/dist/runtime/editor/features/search/index.vue +7 -2
- package/dist/runtime/editor/features/selection/AddButtons/Renderer/index.vue +1 -1
- package/dist/runtime/editor/features/selection/AddButtons/index.vue +26 -2
- package/dist/runtime/editor/features/selection/Renderer/index.vue +23 -5
- package/dist/runtime/editor/features/selection/Renderer/vertex.glsl +5 -2
- package/dist/runtime/editor/features/selection/index.vue +17 -5
- package/dist/runtime/editor/features/translations/index.vue +17 -11
- package/dist/runtime/editor/helpers/dropTargets/index.d.ts +1 -1
- package/dist/runtime/editor/helpers/dropTargets/index.js +2 -2
- package/dist/runtime/editor/plugins/ItemAction/index.d.vue.ts +4 -1
- package/dist/runtime/editor/plugins/ItemAction/index.vue +9 -3
- package/dist/runtime/editor/plugins/ItemAction/index.vue.d.ts +4 -1
- package/dist/runtime/editor/providers/keyboard.js +8 -5
- package/dist/runtime/editor/providers/permissions.d.ts +22 -1
- package/dist/runtime/editor/providers/permissions.js +99 -3
- package/dist/runtime/editor/providers/selection.d.ts +2 -1
- package/dist/runtime/editor/providers/selection.js +10 -5
- package/dist/runtime/editor/translations/de.json +96 -0
- package/dist/runtime/editor/translations/fr.json +96 -0
- package/dist/runtime/editor/translations/gsw_CH.json +515 -419
- package/dist/runtime/editor/translations/it.json +96 -0
- package/dist/runtime/editor/types/definitions.d.ts +2 -0
- package/package.json +1 -1
|
@@ -31,6 +31,7 @@ uniform vec3 u_color_accent;
|
|
|
31
31
|
uniform vec3 u_color_teal;
|
|
32
32
|
uniform vec3 u_color_white;
|
|
33
33
|
uniform vec3 u_color_lime;
|
|
34
|
+
uniform vec3 u_color_yellow;
|
|
34
35
|
|
|
35
36
|
// The transformed quad for the fragment shader.
|
|
36
37
|
out vec4 v_quad;
|
|
@@ -140,8 +141,10 @@ void main() {
|
|
|
140
141
|
v_dash_cycle = 14.0 - u_scale * 1.0;
|
|
141
142
|
v_rect_size_artboard = vec2(hoverPos.z, hoverPos.w);
|
|
142
143
|
|
|
143
|
-
// Select color based on type: 0 = mono, 1 = accent, 2 = teal, 3 = white (inverted), 4 = lime (library)
|
|
144
|
-
if (hoverType >
|
|
144
|
+
// Select color based on type: 0 = mono, 1 = accent, 2 = teal, 3 = white (inverted), 4 = lime (library), 5 = yellow (restricted)
|
|
145
|
+
if (hoverType > 4.5) {
|
|
146
|
+
v_color = u_color_yellow;
|
|
147
|
+
} else if (hoverType > 3.5) {
|
|
145
148
|
v_color = u_color_lime;
|
|
146
149
|
} else if (hoverType > 2.5) {
|
|
147
150
|
v_color = u_color_white;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
v-if="isReusable"
|
|
4
4
|
id="library_detach"
|
|
5
5
|
:title="$t('libraryDetach', 'Detach from library')"
|
|
6
|
+
:disabled="detachDisabledReason"
|
|
6
7
|
icon="reusable-detach"
|
|
7
8
|
edit-only
|
|
8
9
|
multiple
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
v-else-if="!isReusable"
|
|
14
15
|
id="library_make_reusable"
|
|
15
16
|
:title="$t('libraryAdd', 'Add to library...')"
|
|
16
|
-
:disabled="
|
|
17
|
+
:disabled="makeReusableDisabledReason"
|
|
17
18
|
edit-only
|
|
18
19
|
icon="reusable"
|
|
19
20
|
:weight="-70"
|
|
@@ -82,6 +83,12 @@ const showReusableDialog = useDialog("library-reusable", "center");
|
|
|
82
83
|
const userCanCreateLibraryItem = computed(
|
|
83
84
|
() => permissions.hasPermission("create_library_item")
|
|
84
85
|
);
|
|
86
|
+
const canAddFromLibrary = computed(
|
|
87
|
+
() => permissions.checkBlockBundlePermission(fromLibraryBlockBundle, "add")
|
|
88
|
+
);
|
|
89
|
+
const canEditFromLibrary = computed(
|
|
90
|
+
() => permissions.checkBlockBundlePermission(fromLibraryBlockBundle, "edit")
|
|
91
|
+
);
|
|
85
92
|
async function selectNewlyAdded(cb) {
|
|
86
93
|
const uuidsBefore = state.getAllUuids();
|
|
87
94
|
await cb();
|
|
@@ -93,7 +100,7 @@ async function selectNewlyAdded(cb) {
|
|
|
93
100
|
eventBus.emit("select", newUuid);
|
|
94
101
|
}
|
|
95
102
|
const onDetach = async () => {
|
|
96
|
-
if (!adapter.detachReusableBlock || !selection.uuids.value.length) {
|
|
103
|
+
if (!adapter.detachReusableBlock || !selection.uuids.value.length || detachDisabledReason.value) {
|
|
97
104
|
return;
|
|
98
105
|
}
|
|
99
106
|
await selectNewlyAdded(
|
|
@@ -106,7 +113,7 @@ const onDetach = async () => {
|
|
|
106
113
|
};
|
|
107
114
|
const placedAction = ref(null);
|
|
108
115
|
const onAddLibraryItem = async (uuid) => {
|
|
109
|
-
if (!placedAction.value || !adapter.addLibraryItem) {
|
|
116
|
+
if (!placedAction.value || !adapter.addLibraryItem || !canAddFromLibrary.value) {
|
|
110
117
|
return;
|
|
111
118
|
}
|
|
112
119
|
await state.mutateWithLoadingState(
|
|
@@ -166,9 +173,46 @@ const fromLibraryAllowedInList = computed(() => {
|
|
|
166
173
|
}
|
|
167
174
|
return types.allowedTypesInList.value.includes(fromLibraryBlockBundle);
|
|
168
175
|
});
|
|
169
|
-
const
|
|
170
|
-
(
|
|
171
|
-
|
|
176
|
+
const detachDisabledReason = computed(() => {
|
|
177
|
+
if (!canEditFromLibrary.value) {
|
|
178
|
+
return $t(
|
|
179
|
+
"libraryDetachNoPermission",
|
|
180
|
+
"You do not have permission to detach this block."
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
});
|
|
185
|
+
const makeReusableDisabledReason = computed(() => {
|
|
186
|
+
if (isReusable.value) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
if (!userCanCreateLibraryItem.value) {
|
|
190
|
+
return $t(
|
|
191
|
+
"libraryAddNoPermission",
|
|
192
|
+
"You do not have permission to create library items."
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
const item = selection.item.value;
|
|
196
|
+
if (item && !permissions.checkBlockBundlePermission(item.bundle, "edit")) {
|
|
197
|
+
return $t(
|
|
198
|
+
"libraryAddNoEditPermission",
|
|
199
|
+
"You do not have permission to edit this block."
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
if (!itemBundle?.value?.allowReusable) {
|
|
203
|
+
return $t(
|
|
204
|
+
"libraryAddNotSupported",
|
|
205
|
+
"This block type cannot be made reusable."
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
if (!fromLibraryAllowedInList.value) {
|
|
209
|
+
return $t(
|
|
210
|
+
"libraryAddNotAllowedInField",
|
|
211
|
+
"Reusable blocks are not allowed in this field."
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return false;
|
|
215
|
+
});
|
|
172
216
|
const editingLibraryItem = ref(null);
|
|
173
217
|
onBlokkliEvent("library:edit-item", function(e) {
|
|
174
218
|
editingLibraryItem.value = {
|
|
@@ -186,7 +230,7 @@ function onSubmitLibraryItem() {
|
|
|
186
230
|
}
|
|
187
231
|
defineDropHandler("reusable", {
|
|
188
232
|
async execute({ items, host, afterUuid }) {
|
|
189
|
-
if (adapter.addLibraryItem) {
|
|
233
|
+
if (adapter.addLibraryItem && canAddFromLibrary.value) {
|
|
190
234
|
await state.mutateWithLoadingState(
|
|
191
235
|
() => adapter.addLibraryItem({
|
|
192
236
|
libraryItemUuid: items[0].libraryItemUuid,
|
|
@@ -198,7 +242,7 @@ defineDropHandler("reusable", {
|
|
|
198
242
|
}
|
|
199
243
|
});
|
|
200
244
|
defineAddAction(() => {
|
|
201
|
-
if (!adapter.addLibraryItem || !adapter.getLibraryItems || !isSupportedOnEntity.value) {
|
|
245
|
+
if (!adapter.addLibraryItem || !adapter.getLibraryItems || !isSupportedOnEntity.value || !canAddFromLibrary.value) {
|
|
202
246
|
return;
|
|
203
247
|
}
|
|
204
248
|
return {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
options: {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}[];
|
|
7
|
+
modelValue?: string;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: string) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="root"
|
|
4
|
+
class="bk-media-library-filter-select"
|
|
5
|
+
:class="{ 'bk-is-open': isOpen }"
|
|
6
|
+
@keydown.stop="onKeydown"
|
|
7
|
+
>
|
|
8
|
+
<button type="button" @click="toggle">
|
|
9
|
+
<div>
|
|
10
|
+
<span class="bk-media-library-filter-select-label">{{ label }}</span>
|
|
11
|
+
<span
|
|
12
|
+
v-if="selectedLabel"
|
|
13
|
+
class="bk-media-library-filter-select-value"
|
|
14
|
+
>{{ selectedLabel }}</span
|
|
15
|
+
>
|
|
16
|
+
</div>
|
|
17
|
+
<Icon name="bk_mdi_arrow_drop_down" />
|
|
18
|
+
</button>
|
|
19
|
+
<div
|
|
20
|
+
v-if="isOpen"
|
|
21
|
+
class="bk-media-library-filter-select-dropdown bk-scrollbar-dark"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
v-if="options.length > 10"
|
|
25
|
+
class="bk-media-library-filter-select-search"
|
|
26
|
+
>
|
|
27
|
+
<input
|
|
28
|
+
ref="searchInput"
|
|
29
|
+
v-model="search"
|
|
30
|
+
class="bk-form-input bk-is-small"
|
|
31
|
+
type="text"
|
|
32
|
+
:placeholder="$t('filterSelectSearch', 'Search...')"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
<ul ref="listEl">
|
|
36
|
+
<li v-for="(option, index) in filteredOptions" :key="option.value">
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
:class="{
|
|
40
|
+
'bk-is-active': option.value === modelValue,
|
|
41
|
+
'bk-is-highlighted': index === highlightedIndex
|
|
42
|
+
}"
|
|
43
|
+
@click="select(option.value)"
|
|
44
|
+
@mouseenter="highlightedIndex = index"
|
|
45
|
+
>
|
|
46
|
+
{{ option.label }}
|
|
47
|
+
</button>
|
|
48
|
+
</li>
|
|
49
|
+
<li
|
|
50
|
+
v-if="!filteredOptions.length"
|
|
51
|
+
class="bk-media-library-filter-select-empty"
|
|
52
|
+
>
|
|
53
|
+
{{ $t("filterSelectNoResults", "No results") }}
|
|
54
|
+
</li>
|
|
55
|
+
</ul>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup>
|
|
61
|
+
import {
|
|
62
|
+
ref,
|
|
63
|
+
computed,
|
|
64
|
+
nextTick,
|
|
65
|
+
watch,
|
|
66
|
+
useTemplateRef,
|
|
67
|
+
onBeforeUnmount,
|
|
68
|
+
useBlokkli
|
|
69
|
+
} from "#imports";
|
|
70
|
+
import { Icon } from "#blokkli/editor/components";
|
|
71
|
+
const { $t } = useBlokkli();
|
|
72
|
+
const props = defineProps({
|
|
73
|
+
label: { type: String, required: true },
|
|
74
|
+
options: { type: Array, required: true },
|
|
75
|
+
modelValue: { type: String, required: false }
|
|
76
|
+
});
|
|
77
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
78
|
+
const isOpen = ref(false);
|
|
79
|
+
const search = ref("");
|
|
80
|
+
const highlightedIndex = ref(-1);
|
|
81
|
+
const searchInput = useTemplateRef("searchInput");
|
|
82
|
+
const root = useTemplateRef("root");
|
|
83
|
+
const listEl = useTemplateRef("listEl");
|
|
84
|
+
const selectedLabel = computed(() => {
|
|
85
|
+
const option = props.options.find((o) => o.value === props.modelValue);
|
|
86
|
+
return option?.label ?? "";
|
|
87
|
+
});
|
|
88
|
+
const filteredOptions = computed(() => {
|
|
89
|
+
if (!search.value) {
|
|
90
|
+
return props.options;
|
|
91
|
+
}
|
|
92
|
+
const term = search.value.toLowerCase();
|
|
93
|
+
return props.options.filter((o) => o.label.toLowerCase().includes(term));
|
|
94
|
+
});
|
|
95
|
+
watch(filteredOptions, () => {
|
|
96
|
+
highlightedIndex.value = -1;
|
|
97
|
+
});
|
|
98
|
+
function scrollToHighlighted() {
|
|
99
|
+
if (!listEl.value || highlightedIndex.value < 0) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const buttons = listEl.value.querySelectorAll("button");
|
|
103
|
+
buttons[highlightedIndex.value]?.scrollIntoView({ block: "nearest" });
|
|
104
|
+
}
|
|
105
|
+
function toggle() {
|
|
106
|
+
isOpen.value = !isOpen.value;
|
|
107
|
+
if (isOpen.value) {
|
|
108
|
+
search.value = "";
|
|
109
|
+
highlightedIndex.value = -1;
|
|
110
|
+
nextTick(() => {
|
|
111
|
+
searchInput.value?.focus();
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function select(value) {
|
|
116
|
+
emit("update:modelValue", value);
|
|
117
|
+
isOpen.value = false;
|
|
118
|
+
}
|
|
119
|
+
function onKeydown(e) {
|
|
120
|
+
if (!isOpen.value) {
|
|
121
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
toggle();
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const options = filteredOptions.value;
|
|
128
|
+
switch (e.key) {
|
|
129
|
+
case "ArrowDown":
|
|
130
|
+
e.preventDefault();
|
|
131
|
+
highlightedIndex.value = highlightedIndex.value < options.length - 1 ? highlightedIndex.value + 1 : 0;
|
|
132
|
+
nextTick(scrollToHighlighted);
|
|
133
|
+
break;
|
|
134
|
+
case "ArrowUp":
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
highlightedIndex.value = highlightedIndex.value > 0 ? highlightedIndex.value - 1 : options.length - 1;
|
|
137
|
+
nextTick(scrollToHighlighted);
|
|
138
|
+
break;
|
|
139
|
+
case "Enter": {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
const option = options[highlightedIndex.value];
|
|
142
|
+
if (option) {
|
|
143
|
+
select(option.value);
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
case "Escape":
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
isOpen.value = false;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function onClickOutside(e) {
|
|
154
|
+
if (root.value && !root.value.contains(e.target)) {
|
|
155
|
+
isOpen.value = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
watch(isOpen, (open) => {
|
|
159
|
+
if (open) {
|
|
160
|
+
document.addEventListener("click", onClickOutside, true);
|
|
161
|
+
} else {
|
|
162
|
+
document.removeEventListener("click", onClickOutside, true);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
onBeforeUnmount(() => {
|
|
166
|
+
document.removeEventListener("click", onClickOutside, true);
|
|
167
|
+
});
|
|
168
|
+
</script>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
label: string;
|
|
3
|
+
options: {
|
|
4
|
+
value: string;
|
|
5
|
+
label: string;
|
|
6
|
+
}[];
|
|
7
|
+
modelValue?: string;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: string) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="bk bk-media-library">
|
|
2
|
+
<div class="bk bk-media-library bk-scrollbar-light">
|
|
3
3
|
<div v-if="status === 'pending'" class="bk-loading">
|
|
4
4
|
<Icon name="loader" />
|
|
5
5
|
</div>
|
|
@@ -18,20 +18,12 @@
|
|
|
18
18
|
:placeholder="filter.placeholder"
|
|
19
19
|
/>
|
|
20
20
|
</label>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
v-for="option in filter.options"
|
|
28
|
-
:key="option.value"
|
|
29
|
-
:value="option.value"
|
|
30
|
-
>
|
|
31
|
-
{{ option.label }}
|
|
32
|
-
</option>
|
|
33
|
-
</select>
|
|
34
|
-
</label>
|
|
21
|
+
<FilterSelect
|
|
22
|
+
v-else-if="filter.type === 'options'"
|
|
23
|
+
v-model="filterValues[filter.name]"
|
|
24
|
+
:label="filter.label"
|
|
25
|
+
:options="filter.options"
|
|
26
|
+
/>
|
|
35
27
|
<FormToggle
|
|
36
28
|
v-else-if="filter.type === 'checkbox'"
|
|
37
29
|
v-model="filterValues[filter.name]"
|
|
@@ -41,7 +33,7 @@
|
|
|
41
33
|
</div>
|
|
42
34
|
<div
|
|
43
35
|
ref="listEl"
|
|
44
|
-
class="bk-media-library-items
|
|
36
|
+
class="bk-media-library-items"
|
|
45
37
|
:class="'bk-is-' + listView"
|
|
46
38
|
>
|
|
47
39
|
<Sortli no-transition :get-drag-items="getDragItems" :build-item>
|
|
@@ -85,6 +77,7 @@ import {
|
|
|
85
77
|
FormToggle
|
|
86
78
|
} from "#blokkli/editor/components";
|
|
87
79
|
import Item from "./Item.vue";
|
|
80
|
+
import FilterSelect from "./FilterSelect/index.vue";
|
|
88
81
|
import { falsy } from "#blokkli/helpers";
|
|
89
82
|
import { onBlokkliEvent } from "#blokkli/editor/composables";
|
|
90
83
|
defineProps({
|
|
@@ -139,6 +132,7 @@ const toggleListView = () => {
|
|
|
139
132
|
listView.value = listView.value === "grid" ? "horizontal" : "grid";
|
|
140
133
|
};
|
|
141
134
|
const filterValues = ref({});
|
|
135
|
+
const defaultsApplied = ref(false);
|
|
142
136
|
watch(key, () => {
|
|
143
137
|
page.value = 0;
|
|
144
138
|
});
|
|
@@ -162,6 +156,17 @@ const items = computed(() => data.value?.items || []);
|
|
|
162
156
|
const filters = computed(() => {
|
|
163
157
|
return data.value?.filters ?? [];
|
|
164
158
|
});
|
|
159
|
+
watch(filters, (newFilters) => {
|
|
160
|
+
if (defaultsApplied.value || !newFilters.length) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
defaultsApplied.value = true;
|
|
164
|
+
for (const filter of newFilters) {
|
|
165
|
+
if ("defaultValue" in filter && filter.defaultValue !== void 0 && filterValues.value[filter.name] === void 0) {
|
|
166
|
+
filterValues.value[filter.name] = filter.defaultValue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
});
|
|
165
170
|
const firstSelectedBundle = computed(() => {
|
|
166
171
|
if (selected.value.length) {
|
|
167
172
|
const item = items.value.find((v) => v.mediaId === selected.value[0]);
|
|
@@ -30,7 +30,7 @@ defineBlokkliFeature({
|
|
|
30
30
|
description: "Implements a media library to easily drag and drop media like images or videos.",
|
|
31
31
|
requiredAdapterMethods: ["mediaLibraryGetResults", "mediaLibraryAddBlock"]
|
|
32
32
|
});
|
|
33
|
-
const { $t, adapter, state, types, directive } = useBlokkli();
|
|
33
|
+
const { $t, adapter, state, types, directive, permissions } = useBlokkli();
|
|
34
34
|
const ERROR_MESSAGE = $t(
|
|
35
35
|
"mediaLibraryReplaceFailed",
|
|
36
36
|
"Failed to replace media."
|
|
@@ -55,6 +55,9 @@ defineDropAreas((dragItems) => {
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
const isBlock = field.type === itemEntityType;
|
|
58
|
+
if (isBlock && (!permissions.checkBlockBundlePermission(field.bundle, "edit") || permissions.blockHasRestrictedAncestor(field.uuid))) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
58
61
|
const draggableHost = {
|
|
59
62
|
uuid: field.uuid,
|
|
60
63
|
type: field.type,
|
|
@@ -106,7 +109,9 @@ defineDropHandler("media_library", {
|
|
|
106
109
|
return [];
|
|
107
110
|
}
|
|
108
111
|
const item = items[0];
|
|
109
|
-
return field.allowedBundles.filter(
|
|
112
|
+
return field.allowedBundles.filter(
|
|
113
|
+
(b) => item.itemBundles.includes(b) && permissions.checkBlockBundlePermission(b, "add")
|
|
114
|
+
);
|
|
110
115
|
},
|
|
111
116
|
async execute({ items, host, afterUuid, bundle }) {
|
|
112
117
|
if (adapter.mediaLibraryAddBlock && items.length === 1) {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "twgl.js";
|
|
16
16
|
import { RectangleBufferCollector } from "#blokkli/editor/helpers/webgl";
|
|
17
17
|
import { defineRenderer, useDebugLogger } from "#blokkli/editor/composables";
|
|
18
|
-
const { eventBus, dom, theme, animation, ui, blocks } = useBlokkli();
|
|
18
|
+
const { eventBus, dom, theme, animation, ui, blocks, permissions } = useBlokkli();
|
|
19
19
|
const logger = useDebugLogger();
|
|
20
20
|
const props = defineProps({
|
|
21
21
|
startX: { type: Number, required: true },
|
|
@@ -43,6 +43,9 @@ class MultiSelectRectangleBufferCollector extends RectangleBufferCollector {
|
|
|
43
43
|
if (!block) {
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
|
+
if (permissions.blockHasRestrictedAncestor(uuid)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
46
49
|
const el = dom.getDragElement(block);
|
|
47
50
|
if (!el) {
|
|
48
51
|
continue;
|
|
@@ -58,7 +58,7 @@ defineBlokkliFeature({
|
|
|
58
58
|
label: "Search",
|
|
59
59
|
description: "Provides an overlay with shortcut to search for blocks on the current page or existing content to add as blocks."
|
|
60
60
|
});
|
|
61
|
-
const { $t, selection, ui, adapter, state, types, directive } = useBlokkli();
|
|
61
|
+
const { $t, selection, ui, adapter, state, types, directive, permissions } = useBlokkli();
|
|
62
62
|
const ERROR_MESSAGE = $t(
|
|
63
63
|
"searchContentReplaceFailed",
|
|
64
64
|
"Failed to replace content."
|
|
@@ -79,6 +79,9 @@ defineDropAreas((dragItems) => {
|
|
|
79
79
|
if (field.type !== itemEntityType) {
|
|
80
80
|
return;
|
|
81
81
|
}
|
|
82
|
+
if (!permissions.checkBlockBundlePermission(field.bundle, "edit") || permissions.blockHasRestrictedAncestor(field.uuid)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
82
85
|
const config = types.getDroppableFieldConfig(field.fieldName, field);
|
|
83
86
|
const allowedBundles = config.allowed.find(
|
|
84
87
|
(v) => v.type === searchItem.entityType
|
|
@@ -115,7 +118,9 @@ defineDropAreas((dragItems) => {
|
|
|
115
118
|
defineDropHandler("search_content", {
|
|
116
119
|
resolveBundles({ items, field }) {
|
|
117
120
|
const item = items[0];
|
|
118
|
-
return field.allowedBundles.filter(
|
|
121
|
+
return field.allowedBundles.filter(
|
|
122
|
+
(b) => item.itemBundles.includes(b) && permissions.checkBlockBundlePermission(b, "add")
|
|
123
|
+
);
|
|
119
124
|
},
|
|
120
125
|
async execute({ items, host, afterUuid, bundle }) {
|
|
121
126
|
if (!adapter.addContentSearchItem) {
|
|
@@ -52,7 +52,7 @@ const currentUuid = ref("");
|
|
|
52
52
|
const currentBundleLabel = ref("");
|
|
53
53
|
const currentSingleAllowedBundleLabel = ref(null);
|
|
54
54
|
const tooltipData = computed(() => {
|
|
55
|
-
if (hoveredCircle.value < 0) {
|
|
55
|
+
if (hoveredCircle.value < 0 || ui.openTooltip.value) {
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
const index = hoveredCircle.value;
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
:anchor-el="addData.anchorEl"
|
|
9
9
|
:anchor-coordinates="addData.anchorCoordinates"
|
|
10
10
|
:label="addData.label"
|
|
11
|
+
:field="addData.field"
|
|
11
12
|
@select="onSelectBundle"
|
|
12
13
|
@close="closeOverlay"
|
|
13
14
|
@action="onSelectAction"
|
|
15
|
+
@fragment="onSelectFragment"
|
|
14
16
|
/>
|
|
15
17
|
</BlokkliTransition>
|
|
16
18
|
</Teleport>
|
|
@@ -59,7 +61,9 @@ const {
|
|
|
59
61
|
fields,
|
|
60
62
|
animation,
|
|
61
63
|
context,
|
|
62
|
-
selection
|
|
64
|
+
selection,
|
|
65
|
+
permissions,
|
|
66
|
+
adapter
|
|
63
67
|
} = useBlokkli();
|
|
64
68
|
const isLocked = ref(false);
|
|
65
69
|
const shouldRender = computed(() => {
|
|
@@ -258,6 +262,21 @@ function onSelectAction(action) {
|
|
|
258
262
|
});
|
|
259
263
|
closeOverlay();
|
|
260
264
|
}
|
|
265
|
+
async function onSelectFragment(name) {
|
|
266
|
+
const fragmentsAddBlock = adapter.fragmentsAddBlock;
|
|
267
|
+
if (!addData.value || !fragmentsAddBlock) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const { host, preceedingUuid } = addData.value;
|
|
271
|
+
closeOverlay();
|
|
272
|
+
await state.mutateWithLoadingState(
|
|
273
|
+
() => fragmentsAddBlock({
|
|
274
|
+
name,
|
|
275
|
+
host: { ...host },
|
|
276
|
+
preceedingUuid
|
|
277
|
+
})
|
|
278
|
+
);
|
|
279
|
+
}
|
|
261
280
|
const cache = /* @__PURE__ */ new Map();
|
|
262
281
|
function clearAllCache() {
|
|
263
282
|
cache.clear();
|
|
@@ -349,7 +368,12 @@ onBlokkliEvent("state:reloaded", () => {
|
|
|
349
368
|
}
|
|
350
369
|
});
|
|
351
370
|
function setAddData(key, field, label, preceedingUuid, anchorEl, anchorCoordinates) {
|
|
352
|
-
|
|
371
|
+
if (field.hostEntityType === itemEntityType && (!permissions.checkBlockBundlePermission(field.hostEntityBundle, "edit") || permissions.blockHasRestrictedAncestor(field.hostEntityUuid))) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const allowedBundles = field.allowedBundles.filter(
|
|
375
|
+
(v) => permissions.checkBlockBundlePermission(v, "add")
|
|
376
|
+
);
|
|
353
377
|
if (allowedBundles.length === 0) {
|
|
354
378
|
return;
|
|
355
379
|
}
|
|
@@ -22,7 +22,7 @@ const props = defineProps({
|
|
|
22
22
|
blocks: { type: Array, required: true },
|
|
23
23
|
hasHostSelected: { type: Boolean, required: true }
|
|
24
24
|
});
|
|
25
|
-
const { animation, theme, dom, ui, state } = useBlokkli();
|
|
25
|
+
const { animation, theme, dom, ui, state, permissions } = useBlokkli();
|
|
26
26
|
class SelectionRectangleBufferCollector extends RectangleBufferCollector {
|
|
27
27
|
uuids = [];
|
|
28
28
|
lastCount = 0;
|
|
@@ -50,7 +50,8 @@ class SelectionRectangleBufferCollector extends RectangleBufferCollector {
|
|
|
50
50
|
y: 0,
|
|
51
51
|
radius: [0, 0, 0, 0],
|
|
52
52
|
isInverted: false,
|
|
53
|
-
isFromLibrary: false
|
|
53
|
+
isFromLibrary: false,
|
|
54
|
+
isRestricted: false
|
|
54
55
|
},
|
|
55
56
|
3
|
|
56
57
|
// Type 3 = host selection
|
|
@@ -70,8 +71,11 @@ class SelectionRectangleBufferCollector extends RectangleBufferCollector {
|
|
|
70
71
|
}
|
|
71
72
|
const style = ui.lowPerformanceMode.value ? null : theme.getDraggableStyle(el);
|
|
72
73
|
const isFromLibrary = state.fromLibraryUuids.value.includes(block.uuid);
|
|
74
|
+
const isRestricted = !permissions.checkBlockBundlePermission(block.bundle, "edit") || !permissions.checkBlockBundlePermission(block.bundle, "delete") || !permissions.checkBlockBundlePermission(block.bundle, "add");
|
|
73
75
|
let type = 0;
|
|
74
|
-
if (
|
|
76
|
+
if (isRestricted) {
|
|
77
|
+
type = 4;
|
|
78
|
+
} else if (isFromLibrary) {
|
|
75
79
|
type = 2;
|
|
76
80
|
} else if (style?.isInverted) {
|
|
77
81
|
type = 1;
|
|
@@ -85,7 +89,8 @@ class SelectionRectangleBufferCollector extends RectangleBufferCollector {
|
|
|
85
89
|
y: rect.y,
|
|
86
90
|
radius: style?.radius ?? [0, 0, 0, 0],
|
|
87
91
|
isInverted: !!style?.isInverted,
|
|
88
|
-
isFromLibrary
|
|
92
|
+
isFromLibrary,
|
|
93
|
+
isRestricted
|
|
89
94
|
},
|
|
90
95
|
type
|
|
91
96
|
);
|
|
@@ -141,6 +146,15 @@ const getColorLibrary = useTransitionedValue(() => {
|
|
|
141
146
|
}
|
|
142
147
|
return theme.lime.value.normal;
|
|
143
148
|
});
|
|
149
|
+
const getColorRestricted = useTransitionedValue(() => {
|
|
150
|
+
if (selectionColorOverride.value) {
|
|
151
|
+
return selectionColorOverride.value;
|
|
152
|
+
}
|
|
153
|
+
if (hasTransformingStyle.value) {
|
|
154
|
+
return theme.orange.value.normal;
|
|
155
|
+
}
|
|
156
|
+
return theme.yellow.value.normal;
|
|
157
|
+
});
|
|
144
158
|
const getColorHost = useTransitionedValue(() => {
|
|
145
159
|
return theme.mono.value[700];
|
|
146
160
|
});
|
|
@@ -161,6 +175,7 @@ const { collector } = defineRenderer("selection-overlay", {
|
|
|
161
175
|
u_color_default: toShaderColor(getColorDefault()),
|
|
162
176
|
u_color_inverted: toShaderColor(getColorInverted()),
|
|
163
177
|
u_color_library: toShaderColor(getColorLibrary()),
|
|
178
|
+
u_color_restricted: toShaderColor(getColorRestricted()),
|
|
164
179
|
u_color_host: toShaderColor(getColorHost()),
|
|
165
180
|
u_artboard_size: [
|
|
166
181
|
ui.artboardSize.value.width,
|
|
@@ -187,6 +202,7 @@ const { collector } = defineRenderer("selection-overlay", {
|
|
|
187
202
|
const colorDefault = rgbaToCss(getColorDefault());
|
|
188
203
|
const colorInverted = rgbaToCss(getColorInverted());
|
|
189
204
|
const colorLibrary = rgbaToCss(getColorLibrary());
|
|
205
|
+
const colorRestricted = rgbaToCss(getColorRestricted());
|
|
190
206
|
const colorHost = rgbaToCss(getColorHost());
|
|
191
207
|
const smoothstepValue = Math.max(
|
|
192
208
|
0,
|
|
@@ -196,7 +212,9 @@ const { collector } = defineRenderer("selection-overlay", {
|
|
|
196
212
|
for (let i = 0; i < rects.length; i++) {
|
|
197
213
|
const rect = rects[i];
|
|
198
214
|
let strokeColor = colorDefault;
|
|
199
|
-
if (rect.
|
|
215
|
+
if (rect.isRestricted) {
|
|
216
|
+
strokeColor = colorRestricted;
|
|
217
|
+
} else if (rect.isFromLibrary) {
|
|
200
218
|
strokeColor = colorLibrary;
|
|
201
219
|
} else if (rect.isInverted) {
|
|
202
220
|
strokeColor = colorInverted;
|
|
@@ -21,6 +21,7 @@ uniform vec2 u_resolution;
|
|
|
21
21
|
uniform vec3 u_color_default;
|
|
22
22
|
uniform vec3 u_color_inverted;
|
|
23
23
|
uniform vec3 u_color_library;
|
|
24
|
+
uniform vec3 u_color_restricted;
|
|
24
25
|
uniform vec3 u_color_host;
|
|
25
26
|
|
|
26
27
|
// The transformed quad for the fragment shader.
|
|
@@ -86,9 +87,11 @@ void main() {
|
|
|
86
87
|
|
|
87
88
|
v_rect_width = adjusted_quad.x;
|
|
88
89
|
|
|
89
|
-
// Set color based on type: 0=default, 1=inverted, 2=library, 3=host
|
|
90
|
+
// Set color based on type: 0=default, 1=inverted, 2=library, 3=host, 4=restricted
|
|
90
91
|
v_color = u_color_default;
|
|
91
|
-
if (a_rect_type >
|
|
92
|
+
if (a_rect_type > 3.5) {
|
|
93
|
+
v_color = u_color_restricted;
|
|
94
|
+
} else if (a_rect_type > 2.5) {
|
|
92
95
|
v_color = u_color_host;
|
|
93
96
|
} else if (a_rect_type > 1.5) {
|
|
94
97
|
v_color = u_color_library;
|