@blokkli/editor 1.0.4 → 1.1.1

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 (78) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +345 -16
  3. package/dist/runtime/adapter/drupal/graphql/base.graphql +2 -1
  4. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +4 -1
  5. package/dist/runtime/adapter/index.d.ts +12 -1
  6. package/dist/runtime/blokkliPlugins/Sidebar/Detached/index.vue +41 -39
  7. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +10 -16
  8. package/dist/runtime/blokkliPlugins/ViewOption/index.vue +2 -0
  9. package/dist/runtime/components/BlokkliField.vue +75 -17
  10. package/dist/runtime/components/BlokkliItem.vue +34 -6
  11. package/dist/runtime/components/BlokkliProvider.vue +18 -1
  12. package/dist/runtime/components/Edit/BlockProxy/index.vue +102 -0
  13. package/dist/runtime/components/Edit/DragInteractions/index.vue +49 -25
  14. package/dist/runtime/components/Edit/DraggableList.vue +140 -30
  15. package/dist/runtime/components/Edit/EditProvider.vue +4 -0
  16. package/dist/runtime/components/Edit/Features/AddList/index.vue +3 -0
  17. package/dist/runtime/components/Edit/Features/Artboard/Overview/index.vue +111 -0
  18. package/dist/runtime/components/Edit/Features/Artboard/Scrollbar/index.vue +47 -0
  19. package/dist/runtime/components/Edit/Features/Artboard/index.vue +301 -9
  20. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +29 -4
  21. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +3 -4
  22. package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +27 -0
  23. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +24 -3
  24. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/fragment.glsl +56 -24
  25. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +184 -29
  26. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/vertex.glsl +36 -16
  27. package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +4 -0
  28. package/dist/runtime/components/Edit/Features/Duplicate/index.vue +1 -13
  29. package/dist/runtime/components/Edit/Features/EditableMask/index.vue +2 -2
  30. package/dist/runtime/components/Edit/Features/History/index.vue +1 -1
  31. package/dist/runtime/components/Edit/Features/Options/Form/Checkbox/index.vue +2 -2
  32. package/dist/runtime/components/Edit/Features/Options/Form/Checkboxes/index.vue +28 -25
  33. package/dist/runtime/components/Edit/Features/Options/Form/Color/index.vue +1 -1
  34. package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +67 -39
  35. package/dist/runtime/components/Edit/Features/Options/Form/Number/index.vue +6 -2
  36. package/dist/runtime/components/Edit/Features/Options/Form/Radios/index.vue +1 -1
  37. package/dist/runtime/components/Edit/Features/Options/Form/Range/index.vue +2 -2
  38. package/dist/runtime/components/Edit/Features/Options/Form/Text/index.vue +2 -1
  39. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +83 -33
  40. package/dist/runtime/components/Edit/Features/ProxyView/index.vue +38 -0
  41. package/dist/runtime/components/Edit/Features/Publish/index.vue +53 -6
  42. package/dist/runtime/components/Edit/Features/Search/Overlay/index.vue +3 -13
  43. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +1 -1
  44. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +2 -0
  45. package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +3 -3
  46. package/dist/runtime/components/Edit/Features/Structure/index.vue +3 -3
  47. package/dist/runtime/components/Edit/ScrollBoundary/index.vue +24 -0
  48. package/dist/runtime/components/Edit/index.d.ts +2 -1
  49. package/dist/runtime/components/Edit/index.js +3 -1
  50. package/dist/runtime/composables/defineBlokkli.js +10 -5
  51. package/dist/runtime/constants/index.d.ts +1 -1
  52. package/dist/runtime/constants/index.js +6 -1
  53. package/dist/runtime/css/output.css +1 -1
  54. package/dist/runtime/helpers/animationProvider.js +10 -4
  55. package/dist/runtime/helpers/domProvider.d.ts +12 -4
  56. package/dist/runtime/helpers/domProvider.js +70 -26
  57. package/dist/runtime/helpers/featuresProvider.d.ts +1 -1
  58. package/dist/runtime/helpers/runtimeHelpers/index.d.ts +6 -0
  59. package/dist/runtime/helpers/runtimeHelpers/index.js +25 -0
  60. package/dist/runtime/helpers/selectionProvider.d.ts +2 -1
  61. package/dist/runtime/helpers/selectionProvider.js +7 -8
  62. package/dist/runtime/helpers/symbols.d.ts +7 -0
  63. package/dist/runtime/helpers/symbols.js +7 -0
  64. package/dist/runtime/helpers/typesProvider.d.ts +1 -1
  65. package/dist/runtime/helpers/uiProvider.d.ts +1 -0
  66. package/dist/runtime/helpers/uiProvider.js +16 -3
  67. package/dist/runtime/helpers/webgl/index.d.ts +6 -1
  68. package/dist/runtime/helpers/webgl/index.js +38 -5
  69. package/dist/runtime/icons/eye.svg +1 -0
  70. package/dist/runtime/types/generatedModuleTypes.d.ts +12 -4
  71. package/dist/runtime/types/index.d.ts +30 -1
  72. package/package.json +7 -5
  73. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.d.ts +0 -204
  74. package/dist/runtime/components/Edit/Features/Artboard/Manager/Artboard.js +0 -748
  75. package/dist/runtime/components/Edit/Features/Artboard/Manager/Scrollbar/index.vue +0 -176
  76. package/dist/runtime/components/Edit/Features/Artboard/Manager/index.vue +0 -317
  77. package/dist/runtime/helpers/Artboard/index.d.ts +0 -16
  78. package/dist/runtime/helpers/Artboard/index.js +0 -20
@@ -1,15 +1,21 @@
1
1
  <template>
2
2
  <div class="bk-blokkli-item-options-item" @keydown.stop>
3
3
  <div
4
+ v-if="showLabel"
4
5
  :class="isGrouped ? 'bk-blokkli-item-options-item-label' : 'bk-tooltip'"
5
6
  >
6
- <span>{{ option.label }}</span>
7
+ <span>{{ label }}</span>
7
8
  </div>
8
- <div class="bk-blokkli-item-options-item-content">
9
+ <div
10
+ class="bk-blokkli-item-options-item-content"
11
+ :class="{
12
+ 'bk-is-grouped': isGrouped,
13
+ }"
14
+ >
9
15
  <OptionRadios
10
16
  v-if="option.type === 'radios'"
11
17
  v-model="value"
12
- :label="option.label"
18
+ :label="label"
13
19
  :options="option.options"
14
20
  :property="property"
15
21
  :display-as="option.displayAs"
@@ -18,32 +24,33 @@
18
24
  v-else-if="option.type === 'checkbox'"
19
25
  v-model="value"
20
26
  :property="property"
21
- :label="option.label"
27
+ :label="label"
22
28
  :value="value"
23
29
  />
24
30
  <OptionCheckboxes
25
31
  v-else-if="option.type === 'checkboxes'"
26
32
  v-model="value"
27
33
  :property="property"
28
- :label="option.label"
29
- :options="option.options"
34
+ :label="label"
35
+ :options="checkboxOptions"
30
36
  :value="value"
37
+ :is-grouped="isGrouped"
31
38
  />
32
39
  <OptionText
33
40
  v-else-if="option.type === 'text'"
34
41
  v-model="value"
35
- :label="option.label"
42
+ :label="label"
36
43
  :type="option.inputType"
37
44
  />
38
45
  <OptionColor
39
46
  v-else-if="option.type === 'color'"
40
47
  v-model="value"
41
- :label="option.label"
48
+ :label="label"
42
49
  />
43
50
  <OptionRange
44
51
  v-else-if="option.type === 'range'"
45
52
  v-model="value"
46
- :label="option.label"
53
+ :label="label"
47
54
  :min="option.min"
48
55
  :max="option.max"
49
56
  :step="option.step"
@@ -51,7 +58,7 @@
51
58
  <OptionNumber
52
59
  v-else-if="option.type === 'number'"
53
60
  v-model="value"
54
- :label="option.label"
61
+ :label="label"
55
62
  :min="option.min"
56
63
  :max="option.max"
57
64
  />
@@ -70,8 +77,9 @@ import OptionRange from './Range/index.vue'
70
77
  import OptionNumber from './Number/index.vue'
71
78
  import type { BlockOptionDefinition } from '#blokkli/types/blokkOptions'
72
79
  import { mapCheckboxTrue } from '#blokkli/helpers/runtimeHelpers'
80
+ import { BK_VISIBLE_LANGUAGES } from '#blokkli/helpers/symbols'
73
81
 
74
- const { state } = useBlokkli()
82
+ const { state, $t: $blokkliText } = useBlokkli()
75
83
 
76
84
  const emit = defineEmits<{
77
85
  (e: 'update', data: string): void
@@ -80,10 +88,53 @@ const emit = defineEmits<{
80
88
  const props = defineProps<{
81
89
  option: BlockOptionDefinition
82
90
  property: string
91
+ mutatedValue: any
83
92
  uuids: string[]
84
93
  isGrouped?: boolean
85
94
  }>()
86
95
 
96
+ const showLabel = computed(() => {
97
+ if (props.isGrouped) {
98
+ if (props.option.type === 'checkbox') {
99
+ return false
100
+ }
101
+ }
102
+
103
+ return true
104
+ })
105
+
106
+ const label = computed(() =>
107
+ $blokkliText(`blockOption_${props.property}_label`, props.option.label),
108
+ )
109
+
110
+ const checkboxOptions = computed<{ value: string; label: string }[]>(() => {
111
+ if (props.option.type !== 'checkboxes') {
112
+ return []
113
+ }
114
+
115
+ if (props.property === BK_VISIBLE_LANGUAGES) {
116
+ return (state.translation.value.availableLanguages || []).map(
117
+ (language) => {
118
+ return {
119
+ value: language.id,
120
+ label: language.name,
121
+ }
122
+ },
123
+ )
124
+ }
125
+
126
+ return Object.entries(props.option.options).map(([value, label]) => {
127
+ return {
128
+ value,
129
+ label,
130
+ }
131
+ })
132
+ })
133
+
134
+ const validCheckboxValues = computed(() =>
135
+ checkboxOptions.value.map((v) => v.value),
136
+ )
137
+
87
138
  const validateValue = (
88
139
  v: string | string[] | boolean | undefined | null | number,
89
140
  ): string | undefined => {
@@ -102,13 +153,12 @@ const validateValue = (
102
153
  } else if (props.option.type === 'checkbox') {
103
154
  return mapCheckboxTrue(v)
104
155
  } else if (props.option.type === 'checkboxes') {
105
- const options = Object.keys(props.option.options || {})
106
156
  const items = Array.isArray(v)
107
157
  ? v
108
158
  : (typeof v === 'string' ? v : '').split(',')
109
159
  return items
110
160
  .filter((key) => {
111
- return options.includes(key)
161
+ return validCheckboxValues.value.includes(key)
112
162
  })
113
163
  .join(',')
114
164
  } else if (props.option.type === 'range' || props.option.type === 'number') {
@@ -120,34 +170,12 @@ const validateValue = (
120
170
  }
121
171
  }
122
172
 
123
- const mutatedValue = computed<string | undefined>(() => {
124
- for (let i = 0; i < props.uuids.length; i++) {
125
- const uuid = props.uuids[i]
126
- const mutatedOptions = state.mutatedOptions[uuid]
127
- if (mutatedOptions) {
128
- const mutatedOption = state.mutatedOptions[uuid]?.[props.property]
129
- if (mutatedOption !== undefined) {
130
- return validateValue(mutatedOption)
131
- }
132
- }
133
- }
134
-
135
- return undefined
136
- })
137
-
138
- const defaultValue = computed<string>(
139
- () => validateValue(props.option.default) || '',
140
- )
141
-
142
- const value = computed<string>({
173
+ const value = computed<string | undefined>({
143
174
  get() {
144
- if (mutatedValue.value === undefined) {
145
- return defaultValue.value
146
- }
147
- return mutatedValue.value
175
+ return validateValue(props.mutatedValue)
148
176
  },
149
- set(value: string) {
150
- emit('update', value)
177
+ set(value: string | undefined) {
178
+ emit('update', value === undefined ? '' : value)
151
179
  },
152
180
  })
153
181
  </script>
@@ -26,13 +26,14 @@ import { Icon } from '#blokkli/components'
26
26
  const props = withDefaults(
27
27
  defineProps<{
28
28
  label: string
29
- modelValue: string
29
+ modelValue?: string
30
30
  min: number
31
31
  max: number
32
32
  type?: string
33
33
  }>(),
34
34
  {
35
35
  type: 'text',
36
+ modelValue: '0',
36
37
  },
37
38
  )
38
39
 
@@ -42,7 +43,7 @@ const emit = defineEmits(['update:modelValue'])
42
43
 
43
44
  const text = computed<string>({
44
45
  get() {
45
- return props.modelValue || '0'
46
+ return props.modelValue
46
47
  },
47
48
  set(v: string | number | undefined) {
48
49
  emit('update:modelValue', (v === undefined ? '' : v).toString())
@@ -50,6 +51,9 @@ const text = computed<string>({
50
51
  })
51
52
 
52
53
  const numeric = computed(() => {
54
+ if (props.modelValue === undefined) {
55
+ return 0
56
+ }
53
57
  const v = Number.parseInt(props.modelValue)
54
58
  if (Number.isNaN(v)) {
55
59
  return 0
@@ -75,7 +75,7 @@ const props = defineProps<{
75
75
  property: string
76
76
  displayAs?: 'radios' | 'colors' | 'grid' | 'icons'
77
77
  options: Record<string, PossibleOptionType>
78
- modelValue: string
78
+ modelValue?: string
79
79
  }>()
80
80
 
81
81
  const emit = defineEmits(['update:modelValue'])
@@ -10,7 +10,7 @@ import { computed } from '#imports'
10
10
 
11
11
  const props = defineProps<{
12
12
  label: string
13
- modelValue: string
13
+ modelValue?: string
14
14
  min: number
15
15
  max: number
16
16
  step: number
@@ -20,7 +20,7 @@ const emit = defineEmits(['update:modelValue'])
20
20
 
21
21
  const text = computed<string>({
22
22
  get() {
23
- return props.modelValue || ''
23
+ return props.modelValue || '0'
24
24
  },
25
25
  set(v: string | number | undefined) {
26
26
  emit('update:modelValue', (v === undefined ? '' : v).toString())
@@ -11,11 +11,12 @@ import { computed } from '#imports'
11
11
  const props = withDefaults(
12
12
  defineProps<{
13
13
  label: string
14
- modelValue: string
14
+ modelValue?: string
15
15
  type?: string
16
16
  }>(),
17
17
  {
18
18
  type: 'text',
19
+ modelValue: '',
19
20
  },
20
21
  )
21
22
 
@@ -10,11 +10,11 @@
10
10
  :key="plugin.property"
11
11
  :option="plugin.option"
12
12
  :property="plugin.property"
13
+ :mutated-value="currentValues[plugin.property]"
13
14
  :uuids="uuids"
14
15
  class="bk-blokkli-item-options-item"
15
16
  :class="{
16
- 'bk-is-disabled':
17
- !state.canEdit.value || state.editMode.value !== 'editing',
17
+ 'bk-is-disabled': isDisabled(plugin),
18
18
  }"
19
19
  @keydown.stop
20
20
  @update="setOptionValue(plugin.property, $event)"
@@ -32,11 +32,11 @@
32
32
  :key="plugin.property"
33
33
  :option="plugin.option"
34
34
  :property="plugin.property"
35
+ :mutated-value="currentValues[plugin.property]"
35
36
  :uuids="uuids"
36
37
  class="bk-blokkli-item-options-item"
37
38
  :class="{
38
- 'bk-is-disabled':
39
- !state.canEdit.value || state.editMode.value !== 'editing',
39
+ 'bk-is-disabled': isDisabled(plugin),
40
40
  }"
41
41
  is-grouped
42
42
  @keydown.stop
@@ -49,7 +49,7 @@
49
49
  <script lang="ts" setup>
50
50
  import { ref, computed, useBlokkli, onBeforeUnmount, onMounted } from '#imports'
51
51
  import { globalOptions } from '#blokkli/definitions'
52
- import { falsy } from '#blokkli/helpers'
52
+ import { falsy, onlyUnique } from '#blokkli/helpers'
53
53
  import OptionsFormItem from './Item.vue'
54
54
  import OptionsFormGroup from './Group.vue'
55
55
  import type {
@@ -60,6 +60,10 @@ import type {
60
60
  import type { BlockOptionDefinition } from '#blokkli/types/blokkOptions'
61
61
  import { optionValueToStorable } from '#blokkli/helpers/options'
62
62
  import { getRuntimeOptionValue } from '#blokkli/helpers/runtimeHelpers'
63
+ import {
64
+ BK_HIDDEN_GLOBALLY,
65
+ BK_VISIBLE_LANGUAGES,
66
+ } from '#blokkli/helpers/symbols'
63
67
 
64
68
  type OptionItem = {
65
69
  property: string
@@ -196,42 +200,70 @@ const availableOptions = computed<OptionItem[]>(() => {
196
200
  })
197
201
  })
198
202
 
203
+ function getOptionValue(
204
+ uuid: string,
205
+ key: string,
206
+ defaultValue: string | boolean | string[] | number,
207
+ ) {
208
+ if (!uuid) {
209
+ return ''
210
+ }
211
+ const blockMutatedOptions = state.mutatedOptions[uuid]
212
+ if (
213
+ blockMutatedOptions !== undefined &&
214
+ blockMutatedOptions[key] !== undefined
215
+ ) {
216
+ return state.mutatedOptions[uuid][key]
217
+ }
218
+ return defaultValue
219
+ }
220
+
199
221
  /**
200
222
  * The current mapped values, same as provided by defineBlokkli.
201
223
  */
202
224
  const currentValues = computed(() => {
203
- const getOptionValue = (
204
- key: string,
205
- defaultValue: string | boolean | string[] | number,
206
- ) => {
207
- const uuid = props.uuids[0]
208
- if (!uuid) {
209
- return ''
210
- }
211
- const blockMutatedOptions = state.mutatedOptions[uuid]
212
- if (
213
- blockMutatedOptions !== undefined &&
214
- blockMutatedOptions[key] !== undefined
215
- ) {
216
- return state.mutatedOptions[uuid][key]
217
- }
218
- return defaultValue
219
- }
220
-
221
225
  return availableOptions.value.reduce<
222
226
  Record<string, string | string[] | boolean | number>
223
227
  >((acc, v) => {
224
- acc[v.property] = getRuntimeOptionValue(
225
- v.option,
226
- getOptionValue(v.property, v.option.default),
227
- )
228
+ // Get all current values.
229
+ const values = props.uuids
230
+ .map((uuid) => {
231
+ return JSON.stringify(
232
+ getRuntimeOptionValue(
233
+ v.option,
234
+ getOptionValue(uuid, v.property, v.option.default),
235
+ ),
236
+ )
237
+ })
238
+ .filter(onlyUnique)
239
+ if (values.length === 1) {
240
+ acc[v.property] = getRuntimeOptionValue(
241
+ v.option,
242
+ getOptionValue(props.uuids[0], v.property, v.option.default),
243
+ )
244
+ } else {
245
+ acc[v.property] = ''
246
+ }
247
+
228
248
  return acc
229
249
  }, {})
230
250
  })
231
251
 
252
+ function filterInternal(item: OptionItem) {
253
+ if (currentValues.value[BK_HIDDEN_GLOBALLY]) {
254
+ return item.property !== BK_VISIBLE_LANGUAGES
255
+ }
256
+
257
+ return true
258
+ }
259
+
260
+ function isInternalOption(property: string) {
261
+ return property === BK_VISIBLE_LANGUAGES || property === BK_HIDDEN_GLOBALLY
262
+ }
263
+
232
264
  const visibleOptions = computed<OptionItem[]>(() => {
233
265
  if (!props.definition.editor?.determineVisibleOptions) {
234
- return availableOptions.value
266
+ return availableOptions.value.filter(filterInternal)
235
267
  }
236
268
 
237
269
  const uuid = props.uuids[0]
@@ -261,9 +293,25 @@ const visibleOptions = computed<OptionItem[]>(() => {
261
293
  fieldListType: block?.hostFieldListType || 'default',
262
294
  })
263
295
 
264
- return availableOptions.value.filter((v) => visibleKeys.includes(v.property))
296
+ return availableOptions.value
297
+ .filter(
298
+ (v) => isInternalOption(v.property) || visibleKeys.includes(v.property),
299
+ )
300
+ .filter(filterInternal)
265
301
  })
266
302
 
303
+ function isDisabled(plugin: OptionItem) {
304
+ if (!state.canEdit.value || state.editMode.value === 'readonly') {
305
+ return true
306
+ }
307
+
308
+ if (isInternalOption(plugin.property)) {
309
+ return false
310
+ }
311
+
312
+ return state.editMode.value !== 'editing'
313
+ }
314
+
267
315
  const singleVisibleOptions = computed(() =>
268
316
  visibleOptions.value.filter((v) => !v.option.group),
269
317
  )
@@ -301,13 +349,15 @@ function setOptionValue(key: string, value: string) {
301
349
  onMounted(() => {
302
350
  props.uuids.forEach((uuid) => {
303
351
  availableOptions.value.forEach((option) => {
352
+ const currentValue = getOptionValue(
353
+ uuid,
354
+ option.property,
355
+ option.option.default,
356
+ )
304
357
  original.set(
305
358
  uuid,
306
359
  option.property,
307
- optionValueToStorable(
308
- option.option,
309
- currentValues.value[option.property],
310
- ),
360
+ optionValueToStorable(option.option, currentValue),
311
361
  )
312
362
  })
313
363
  })
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <PluginViewOption
3
+ id="proxy_view"
4
+ v-model="ui.isProxyMode.value"
5
+ :label="$t('proxyViewToggle', 'Toggle structure view')"
6
+ :title-on="$t('proxyViewShow', 'Show structure view')"
7
+ :title-off="$t('proxyViewHide', 'Show content preview')"
8
+ :tour-text="
9
+ $t(
10
+ 'proxyViewTourText',
11
+ 'Displays the content blocks as a structured view.',
12
+ )
13
+ "
14
+ key-code="P"
15
+ icon="tree"
16
+ />
17
+ </template>
18
+
19
+ <script lang="ts" setup>
20
+ import { useBlokkli, defineBlokkliFeature } from '#imports'
21
+ import { PluginViewOption } from '#blokkli/plugins'
22
+
23
+ defineBlokkliFeature({
24
+ id: 'proxy_view',
25
+ label: 'Proxy View',
26
+ icon: 'tree',
27
+ description: 'Displays the blocks as a structure in the preview.',
28
+ viewports: ['desktop'],
29
+ })
30
+
31
+ const { $t, ui } = useBlokkli()
32
+ </script>
33
+
34
+ <script lang="ts">
35
+ export default {
36
+ name: 'ProxyView',
37
+ }
38
+ </script>
@@ -1,35 +1,76 @@
1
1
  <template>
2
2
  <PluginMenuButton
3
3
  id="publish"
4
- :title="$t('publishLabel', 'Publish')"
5
- :description="$t('publishDescription', 'Make all changes public')"
4
+ :title="publishLabel"
5
+ :description="publishDescription"
6
6
  :disabled="!mutations.length || !canEdit"
7
7
  type="success"
8
8
  :weight="0"
9
- icon="publish"
9
+ :icon="icon"
10
10
  @click="onClick"
11
11
  />
12
12
  </template>
13
13
 
14
14
  <script lang="ts" setup>
15
- import { useBlokkli, defineBlokkliFeature } from '#imports'
15
+ import { useBlokkli, defineBlokkliFeature, computed, useRoute } from '#imports'
16
16
  import { PluginMenuButton } from '#blokkli/plugins'
17
+ import type { BlokkliIcon } from '#blokkli/icons'
17
18
 
18
- const { adapter } = defineBlokkliFeature({
19
+ const { adapter, settings } = defineBlokkliFeature({
19
20
  id: 'publish',
20
21
  icon: 'publish',
21
22
  label: 'Publish',
22
23
  requiredAdapterMethods: ['publish'],
23
24
  description:
24
25
  'Provides a menu button to publish the changes of the current entity.',
26
+ settings: {
27
+ closeAfterPublish: {
28
+ type: 'checkbox',
29
+ label: 'Close editor after publishing',
30
+ default: true,
31
+ group: 'behavior',
32
+ },
33
+ },
25
34
  })
26
35
 
36
+ const route = useRoute()
27
37
  const { state, $t, eventBus, broadcast, context } = useBlokkli()
28
38
  const { mutations, canEdit, mutateWithLoadingState } = state
29
39
 
40
+ const isPublished = computed<boolean>(() => !!state.entity.value.status)
41
+
42
+ const publishLabel = computed(() => {
43
+ // Entity is published. Clicking the button will make the changes go "live".
44
+ if (isPublished.value) {
45
+ return settings.value.closeAfterPublish
46
+ ? $t('publishAndCloseLabel', 'Publish & Close')
47
+ : $t('publishLabel', 'Publish')
48
+ }
49
+
50
+ return settings.value.closeAfterPublish
51
+ ? $t('publishAndCloseLabelUnpublished', 'Save & Close')
52
+ : $t('publishLabelUnpublished', 'Save')
53
+ })
54
+
55
+ const publishDescription = computed(() =>
56
+ isPublished.value
57
+ ? $t('publishDescription', 'Publish all changes.')
58
+ : $t(
59
+ 'publishDescriptionUnpublished',
60
+ 'Save all changes while keeping page unpublished',
61
+ ),
62
+ )
63
+
64
+ const icon = computed<BlokkliIcon>(() =>
65
+ isPublished.value ? 'publish' : 'save',
66
+ )
67
+
30
68
  const onClick = async () => {
31
69
  const success = await mutateWithLoadingState(
32
- adapter.publish,
70
+ () =>
71
+ adapter.publish({
72
+ closeAfterPublish: settings.value.closeAfterPublish,
73
+ }),
33
74
  $t('publishError', 'Changes could not be published.'),
34
75
  $t('publishSuccess', 'Changes published successfully.'),
35
76
  )
@@ -38,11 +79,17 @@ const onClick = async () => {
38
79
  const validations = state.violations.value
39
80
  if (validations.length) {
40
81
  eventBus.emit('publish:failed')
82
+ // Open the validations sidebar when there are validation errors.
83
+ eventBus.emit('sidebar:open', 'violations')
41
84
  }
42
85
  return
43
86
  }
44
87
 
45
88
  broadcast.emit('published', { uuid: context.value.entityUuid })
89
+
90
+ if (settings.value.closeAfterPublish) {
91
+ window.location.href = route.path
92
+ }
46
93
  }
47
94
  </script>
48
95
 
@@ -1,8 +1,7 @@
1
1
  <template>
2
- <div
2
+ <ScrollBoundary
3
3
  class="bk-search-box"
4
4
  @keydown="onKeyDown"
5
- @wheel="onWheel"
6
5
  @mousedown.stop
7
6
  @click.stop
8
7
  >
@@ -63,12 +62,12 @@
63
62
  </template>
64
63
  </div>
65
64
  </div>
66
- </div>
65
+ </ScrollBoundary>
67
66
  </template>
68
67
 
69
68
  <script lang="ts" setup>
70
69
  import { watch, ref, computed, useBlokkli, onMounted, nextTick } from '#imports'
71
- import { Icon } from '#blokkli/components'
70
+ import { Icon, ScrollBoundary } from '#blokkli/components'
72
71
  import { modulo } from '#blokkli/helpers'
73
72
  import ResultsPage from './Results/Page/index.vue'
74
73
  import ResultsContent from './Results/Content/index.vue'
@@ -194,15 +193,6 @@ const onKeyDown = (e: KeyboardEvent) => {
194
193
  }
195
194
  }
196
195
 
197
- function onWheel(e: WheelEvent) {
198
- if (props.isDragging) {
199
- return
200
- }
201
-
202
- e.preventDefault()
203
- e.stopImmediatePropagation()
204
- }
205
-
206
196
  watch(
207
197
  () => props.visible,
208
198
  (isVisible) => {
@@ -100,7 +100,7 @@ class SelectionRectangleBufferCollector extends RectangleBufferCollector<Selecti
100
100
  const collector = new SelectionRectangleBufferCollector(props.gl)
101
101
 
102
102
  const uniforms = {
103
- u_color_default: toShaderColor(theme.accent.value[700]),
103
+ u_color_default: toShaderColor(theme.accent.value[600]),
104
104
  u_color_inverted: [255, 255, 255],
105
105
  }
106
106
 
@@ -56,6 +56,8 @@ const getGroupLabel = (key: SettingsGroup): string => {
56
56
  return $t('settingsAppearance', 'Appearance')
57
57
  } else if (key === 'advanced') {
58
58
  return $t('settingsAdvanced', 'Advanced')
59
+ } else if (key === 'artboard') {
60
+ return $t('settingsArtboard', 'Artboard')
59
61
  }
60
62
  return key
61
63
  }
@@ -15,7 +15,7 @@
15
15
  >
16
16
  <div
17
17
  v-if="
18
- index === 0 && showTargets && !selection.uuidsMap.value[item.uuid]
18
+ index === 0 && showTargets && !selection.isBlockSelected(item.uuid)
19
19
  "
20
20
  :style="targetStyle"
21
21
  class="bk-structure-field-target bk-is-before"
@@ -33,10 +33,10 @@
33
33
  v-if="
34
34
  showTargets &&
35
35
  (!selection.isDraggingExisting.value ||
36
- !selection.uuidsMap.value[item.uuid]) &&
36
+ !selection.isBlockSelected(item.uuid)) &&
37
37
  (!list[index + 1] ||
38
38
  !selection.isDraggingExisting.value ||
39
- !selection.uuidsMap.value[list[index + 1].uuid])
39
+ !selection.isBlockSelected(list[index + 1].uuid))
40
40
  "
41
41
  :style="targetStyle"
42
42
  class="bk-structure-field-target bk-is-after"