@blokkli/editor 1.2.0 → 1.3.0

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 (63) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +1678 -41
  3. package/dist/runtime/adapter/drupal/graphql/base.graphql +14 -3
  4. package/dist/runtime/adapter/drupal/graphql/comments.graphql +6 -1
  5. package/dist/runtime/adapter/drupal/graphql/transform.graphql +10 -2
  6. package/dist/runtime/adapter/drupal/graphqlMiddleware.js +26 -18
  7. package/dist/runtime/adapter/index.d.ts +6 -2
  8. package/dist/runtime/blokkliPlugins/Sidebar/index.vue +4 -1
  9. package/dist/runtime/components/BlokkliField.vue +8 -2
  10. package/dist/runtime/components/Edit/Actions/index.vue +27 -6
  11. package/dist/runtime/components/Edit/AnimationCanvas/index.vue +1 -0
  12. package/dist/runtime/components/Edit/DragInteractions/index.vue +7 -0
  13. package/dist/runtime/components/Edit/EditProvider.vue +23 -5
  14. package/dist/runtime/components/Edit/Features/Artboard/index.vue +4 -0
  15. package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +1 -0
  16. package/dist/runtime/components/Edit/Features/Clipboard/index.vue +3 -1
  17. package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +14 -2
  18. package/dist/runtime/components/Edit/Features/Debug/index.vue +26 -4
  19. package/dist/runtime/components/Edit/Features/Diff/DiffView/index.vue +236 -0
  20. package/dist/runtime/components/Edit/Features/Diff/index.vue +37 -0
  21. package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +14 -4
  22. package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +3 -0
  23. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue +8 -1
  24. package/dist/runtime/components/Edit/Features/EditableField/index.vue +11 -5
  25. package/dist/runtime/components/Edit/Features/EntityTitle/index.vue +1 -0
  26. package/dist/runtime/components/Edit/Features/History/index.vue +3 -1
  27. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue +5 -2
  28. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +10 -3
  29. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue +2 -0
  30. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +4 -1
  31. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +14 -1
  32. package/dist/runtime/components/Edit/Features/Preview/index.vue +2 -1
  33. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue +2 -1
  34. package/dist/runtime/components/Edit/Features/Publish/index.vue +2 -0
  35. package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue +2 -1
  36. package/dist/runtime/components/Edit/Features/Selection/Overlay/fragment.glsl +78 -44
  37. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +8 -8
  38. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +6 -1
  39. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue +23 -2
  40. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +71 -38
  41. package/dist/runtime/components/Edit/Features/Settings/index.vue +4 -0
  42. package/dist/runtime/components/Edit/Features/Transform/index.vue +5 -1
  43. package/dist/runtime/components/Edit/Features/Translations/index.vue +24 -2
  44. package/dist/runtime/components/Edit/Features/index.vue +4 -0
  45. package/dist/runtime/components/Edit/InfoBox/index.vue +14 -0
  46. package/dist/runtime/components/Edit/Messages/index.vue +10 -12
  47. package/dist/runtime/components/Edit/PreviewProvider.vue +9 -2
  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/constants/index.d.ts +1 -1
  51. package/dist/runtime/constants/index.js +1 -0
  52. package/dist/runtime/css/output.css +1 -1
  53. package/dist/runtime/helpers/animationProvider.js +2 -1
  54. package/dist/runtime/helpers/featuresProvider.d.ts +7 -14
  55. package/dist/runtime/helpers/featuresProvider.js +29 -1
  56. package/dist/runtime/helpers/stateProvider.d.ts +1 -0
  57. package/dist/runtime/helpers/stateProvider.js +23 -4
  58. package/dist/runtime/helpers/uiProvider.d.ts +5 -1
  59. package/dist/runtime/helpers/uiProvider.js +10 -2
  60. package/dist/runtime/icons/diff.svg +1 -0
  61. package/dist/runtime/icons/info.svg +1 -0
  62. package/dist/runtime/types/index.d.ts +59 -1
  63. package/package.json +2 -1
@@ -0,0 +1,236 @@
1
+ <template>
2
+ <div class="bk bk-diff-view bk-scrollbar-light">
3
+ <table class="bk-diff-table">
4
+ <thead>
5
+ <tr>
6
+ <th>{{ $t('diffTableChange', 'Change') }}</th>
7
+ <th>{{ $t('diffTableBundle', 'Type') }}</th>
8
+ <th>{{ $t('diffTableProperty', 'Property') }}</th>
9
+ <th>{{ $t('diffTableDiff', 'Diff') }}</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ <template v-for="item in diffItems" :key="item.uuid">
14
+ <tr class="bk-diff-row">
15
+ <td
16
+ :rowspan="Math.max(1, item.props.length)"
17
+ class="bk-diff-status"
18
+ >
19
+ <div
20
+ v-if="item.status === 'added'"
21
+ class="bk-diff-status-label bk-is-added"
22
+ >
23
+ {{ $t('diffStatusAdded', 'Added') }}
24
+ </div>
25
+ <div
26
+ v-else-if="item.status === 'removed'"
27
+ class="bk-diff-status-label bk-is-removed"
28
+ >
29
+ {{ $t('diffStatusDeleted', 'Deleted') }}
30
+ </div>
31
+ <div v-else class="bk-diff-status-label">
32
+ {{ $t('diffStatusEdited', 'Edited') }}
33
+ </div>
34
+ </td>
35
+ <td
36
+ :rowspan="Math.max(1, item.props.length)"
37
+ class="bk-diff-bundle"
38
+ >
39
+ <button
40
+ class="bk-blokkli-item-label"
41
+ :disabled="item.status === 'removed'"
42
+ @click="scrollToBlock(item.uuid)"
43
+ >
44
+ <div class="bk-blokkli-item-label-icon">
45
+ <ItemIcon :bundle="item.bundle" />
46
+ </div>
47
+ <span>{{ getLabel(item.bundle) }}</span>
48
+ </button>
49
+ </td>
50
+
51
+ <template v-if="item.props.length > 0">
52
+ <td>
53
+ <strong>{{ item.props[0].key }}</strong>
54
+ </td>
55
+ <td class="bk-diff-monospace">
56
+ <div class="bk-diff-prop-diff" v-html="item.props[0].diff" />
57
+ </td>
58
+ </template>
59
+ <template v-else>
60
+ <td />
61
+ <td />
62
+ </template>
63
+ </tr>
64
+ <tr
65
+ v-for="prop in item.props.slice(1)"
66
+ :key="prop.key"
67
+ class="bk-diff-prop-row"
68
+ >
69
+ <td>
70
+ <strong>{{ prop.key }}</strong>
71
+ </td>
72
+ <td class="bk-diff-monospace">
73
+ <div class="bk-diff-prop-diff" v-html="prop.diff" />
74
+ </td>
75
+ </tr>
76
+ </template>
77
+ </tbody>
78
+ </table>
79
+ </div>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { computed, useBlokkli } from '#imports'
84
+ import type { FieldListItem, MutatedField } from '#blokkli/types'
85
+ import { ItemIcon } from '#blokkli/components'
86
+ import { getDefaultDefinition } from '#blokkli/definitions'
87
+ import diff from 'html-diff-ts'
88
+
89
+ function getProps(bundle: string, props: any): Record<string, string> {
90
+ const definition = getDefaultDefinition(bundle)
91
+ // Use custom method that builds the diff props.
92
+ if (definition?.editor?.mapDiffProps) {
93
+ return definition.editor.mapDiffProps(props)
94
+ }
95
+
96
+ if (typeof props === 'object') {
97
+ return Object.entries(props).reduce<Record<string, string>>(
98
+ (acc, [key, value]) => {
99
+ if (typeof value === 'string' || typeof value === 'number') {
100
+ acc[key] = value.toString()
101
+ } else if (typeof value === 'object') {
102
+ try {
103
+ // Fallback to a JSON representation of the data.
104
+ const json = JSON.stringify(value, null, 2)
105
+ acc[key] = `<pre>${json}</pre>`
106
+ } catch {
107
+ // Noop.
108
+ }
109
+ }
110
+ return acc
111
+ },
112
+ {},
113
+ )
114
+ }
115
+
116
+ return {}
117
+ }
118
+
119
+ interface DiffItemProp {
120
+ key: string
121
+ diff?: string
122
+ }
123
+
124
+ interface DiffItem {
125
+ uuid: string
126
+ bundle: string
127
+ status: 'changed' | 'added' | 'removed'
128
+ props: DiffItemProp[]
129
+ }
130
+
131
+ const { types, $t, adapter, state, eventBus, dom } = useBlokkli()
132
+
133
+ const stateBefore = await adapter.loadStateAtIndex!(-1).then((v) =>
134
+ adapter.mapState(v),
135
+ )
136
+
137
+ function buildDiffItems(fields?: MutatedField[]): FieldListItem[] {
138
+ const items = (fields || []).flatMap((v) => v.list)
139
+ return items
140
+ }
141
+
142
+ const itemsBefore = computed(() =>
143
+ buildDiffItems(stateBefore.mutatedState?.fields),
144
+ )
145
+ const itemsAfter = computed(() => buildDiffItems(state.mutatedFields.value))
146
+
147
+ const diffItems = computed<DiffItem[]>(() => {
148
+ const diffMap = new Map<string, DiffItem>()
149
+
150
+ itemsBefore.value.forEach((beforeItem) => {
151
+ const afterItem = itemsAfter.value.find(
152
+ (item) => item.uuid === beforeItem.uuid,
153
+ )
154
+ const beforeProps = getProps(beforeItem.bundle, beforeItem.props)
155
+
156
+ // Item has been removed.
157
+ if (!afterItem) {
158
+ diffMap.set(beforeItem.uuid, {
159
+ uuid: beforeItem.uuid,
160
+ bundle: beforeItem.bundle,
161
+ status: 'removed',
162
+ props: Object.entries(beforeProps).map(([key, value]) => ({
163
+ key,
164
+ value,
165
+ diff: diff(value, ''),
166
+ })),
167
+ })
168
+ } else {
169
+ // Item exists in both arrays.
170
+ const afterProps = getProps(afterItem.bundle, afterItem.props)
171
+ const changedProps: DiffItemProp[] = []
172
+
173
+ Object.entries(beforeProps).forEach(([key, beforeValue]) => {
174
+ const afterValue = afterProps[key]
175
+ if (beforeValue !== afterValue) {
176
+ changedProps.push({
177
+ key,
178
+ diff: diff(beforeValue, afterValue),
179
+ })
180
+ }
181
+ })
182
+
183
+ // Check for new properties inside afterProps.
184
+ Object.keys(afterProps).forEach((key) => {
185
+ if (!(key in beforeProps)) {
186
+ changedProps.push({
187
+ key,
188
+ diff: diff('', afterProps[key]),
189
+ })
190
+ }
191
+ })
192
+
193
+ // Only add the item if it has changes.
194
+ if (changedProps.length > 0) {
195
+ diffMap.set(beforeItem.uuid, {
196
+ uuid: beforeItem.uuid,
197
+ bundle: beforeItem.bundle,
198
+ status: 'changed',
199
+ props: changedProps,
200
+ })
201
+ }
202
+ }
203
+ })
204
+
205
+ // Process added items.
206
+ itemsAfter.value.forEach((afterItem) => {
207
+ if (!itemsBefore.value.some((item) => item.uuid === afterItem.uuid)) {
208
+ const afterProps = getProps(afterItem.bundle, afterItem.props)
209
+ diffMap.set(afterItem.uuid, {
210
+ uuid: afterItem.uuid,
211
+ bundle: afterItem.bundle,
212
+ status: 'added',
213
+ props: Object.entries(afterProps).map(([key, value]) => ({
214
+ key,
215
+ diff: diff('', value),
216
+ })),
217
+ })
218
+ }
219
+ })
220
+
221
+ return Array.from(diffMap.values()).sort((a, b) => {
222
+ const aY = dom.getBlockRect(a.uuid)?.y || 0
223
+ const bY = dom.getBlockRect(b.uuid)?.y || 0
224
+ return aY - bY
225
+ })
226
+ })
227
+
228
+ function getLabel(bundle: string): string {
229
+ return types.getBlockBundleDefinition(bundle)?.label || bundle
230
+ }
231
+
232
+ function scrollToBlock(uuid: string) {
233
+ eventBus.emit('scrollIntoView', { uuid, center: true })
234
+ eventBus.emit('select', uuid)
235
+ }
236
+ </script>
@@ -0,0 +1,37 @@
1
+ <template>
2
+ <PluginSidebar
3
+ id="diff"
4
+ :title="$t('diffSidebarTitle', 'Changes')"
5
+ :tour-text="
6
+ $t('diffSidebarTourText', 'Displays all the changes made during editing.')
7
+ "
8
+ icon="diff"
9
+ weight="-400"
10
+ beta
11
+ >
12
+ <DiffView />
13
+ </PluginSidebar>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { useBlokkli, defineBlokkliFeature } from '#imports'
18
+ import { PluginSidebar } from '#blokkli/plugins'
19
+ import DiffView from './DiffView/index.vue'
20
+
21
+ defineBlokkliFeature({
22
+ id: 'diff',
23
+ label: 'Diff',
24
+ icon: 'diff',
25
+ description: 'Displays a diff of all changes in the edit state.',
26
+ requiredAdapterMethods: ['loadStateAtIndex'],
27
+ beta: true,
28
+ })
29
+
30
+ const { $t } = useBlokkli()
31
+ </script>
32
+
33
+ <script lang="ts">
34
+ export default {
35
+ name: 'Diff',
36
+ }
37
+ </script>
@@ -8,10 +8,10 @@
8
8
  <div
9
9
  v-show="activeLabel"
10
10
  class="bk-dragging-overlay-label"
11
- :style="{ backgroundColor: activeColor }"
11
+ :style="{ backgroundColor: currentActiveColor }"
12
12
  >
13
13
  <Icon name="cursor-move" />
14
- <p v-html="prevActiveLabel" />
14
+ <p v-html="currentActiveLabel" />
15
15
  </div>
16
16
  </Transition>
17
17
  <div
@@ -100,13 +100,23 @@ const props = defineProps<{
100
100
  activeLabel?: string
101
101
  }>()
102
102
 
103
- const prevActiveLabel = ref('')
103
+ const currentActiveLabel = ref('')
104
+ const currentActiveColor = ref('')
104
105
 
105
106
  watch(
106
107
  () => props.activeLabel,
107
108
  function (label) {
108
109
  if (label) {
109
- prevActiveLabel.value = label
110
+ currentActiveLabel.value = label
111
+ }
112
+ },
113
+ )
114
+
115
+ watch(
116
+ () => props.activeColor,
117
+ function (color) {
118
+ if (color) {
119
+ currentActiveColor.value = color
110
120
  }
111
121
  },
112
122
  )
@@ -772,6 +772,9 @@ const activeColorRgb = computed(() => {
772
772
  if (active.value?.type === 'drop-area') {
773
773
  return theme.teal.value.normal
774
774
  }
775
+ if (!active.value) {
776
+ return
777
+ }
775
778
  return getColorForField(active.value?.field)
776
779
  })
777
780
 
@@ -53,7 +53,14 @@ function onMessage(e: MessageEvent): void {
53
53
  props.form.id === 'entity:edit' ||
54
54
  props.form.id === 'entity:translate'
55
55
  ) {
56
- eventBus.emit('reloadEntity')
56
+ if (props.form.id === 'entity:translate') {
57
+ const langcode = props.form.translation.id
58
+ eventBus.emit('reloadEntity', () => {
59
+ eventBus.emit('entity:translated', langcode)
60
+ })
61
+ } else {
62
+ eventBus.emit('reloadEntity')
63
+ }
57
64
  } else {
58
65
  eventBus.emit('reloadState')
59
66
  }
@@ -41,7 +41,8 @@ type Editable = {
41
41
  value?: string
42
42
  }
43
43
 
44
- const { selection, adapter, types, $t, dom, runtimeConfig } = useBlokkli()
44
+ const { selection, adapter, types, $t, dom, runtimeConfig, state } =
45
+ useBlokkli()
45
46
  const editable = ref<Editable | null>(null)
46
47
  const hasTransition = ref(false)
47
48
 
@@ -84,9 +85,11 @@ const buildEditable = (
84
85
  )
85
86
 
86
87
  if (!config) {
87
- throw new Error(
88
- `Failed to load editable field config for field "${fieldName}" on entity type "${hostEntityType}" of bundle "${hostEntityBundle}"`,
89
- )
88
+ let message = `Failed to load editable field config for field "${fieldName}" on entity type "${hostEntityType}" of bundle "${hostEntityBundle}"`
89
+ if (uuid) {
90
+ message += ` with uuid "${uuid}"`
91
+ }
92
+ throw new Error(message)
90
93
  }
91
94
 
92
95
  // Adapter doesn't support editable frames, return.
@@ -115,6 +118,9 @@ const buildEditable = (
115
118
  }
116
119
 
117
120
  onBlokkliEvent('editable:focus', (e) => {
121
+ if (!state.canEdit.value) {
122
+ return
123
+ }
118
124
  hasTransition.value = !editable.value
119
125
  editable.value = buildEditable(e.fieldName, e.uuid) || null
120
126
  if (editable.value) {
@@ -157,7 +163,7 @@ defineCommands(() => {
157
163
 
158
164
  return editables.map((v) => {
159
165
  return {
160
- id: 'feature:editable:edit:' + v.fieldName,
166
+ id: 'feature:editable:edit:' + v.host.uuid + ':' + v.fieldName,
161
167
  group: 'selection',
162
168
  label: $t('editableCommandEdit', 'Edit field "@name"').replace(
163
169
  '@name',
@@ -3,6 +3,7 @@
3
3
  <button
4
4
  ref="buttonEl"
5
5
  class="bk-toolbar-button"
6
+ :disabled="!state.canEdit.value"
6
7
  @click="eventBus.emit('editEntity')"
7
8
  >
8
9
  <div class="bk-toolbar-title">
@@ -10,7 +10,7 @@
10
10
  )
11
11
  "
12
12
  icon="history"
13
- weight="-100"
13
+ weight="-800"
14
14
  >
15
15
  <HistoryList :scrolled-to-end="scrolledToEnd" />
16
16
  </PluginSidebar>
@@ -64,6 +64,8 @@ const { adapter, settings } = defineBlokkliFeature({
64
64
  useMouseButtons: {
65
65
  type: 'checkbox',
66
66
  label: 'Use mouse buttons for undo/redo',
67
+ description:
68
+ 'When enabled you can use the backwards/forwards buttons on your mouse to undo and redo.',
67
69
  default: true,
68
70
  group: 'behavior',
69
71
  viewports: ['desktop'],
@@ -46,7 +46,9 @@ const { adapter, settings } = defineBlokkliFeature({
46
46
  showDialogWhenEmpty: {
47
47
  type: 'checkbox',
48
48
  default: true,
49
- label: 'Show import dialog at start when page is empty',
49
+ label: 'Show import dialog at start',
50
+ description:
51
+ 'Displays the import dialog when starting blökkli if the page is empty.',
50
52
  group: 'behavior',
51
53
  },
52
54
  },
@@ -78,7 +80,8 @@ onMounted(() => {
78
80
  if (
79
81
  isEmpty.value &&
80
82
  !state.mutations.value.length &&
81
- settings.value.showDialogWhenEmpty
83
+ settings.value.showDialogWhenEmpty &&
84
+ state.canEdit.value
82
85
  ) {
83
86
  showModal.value = true
84
87
  }
@@ -14,7 +14,15 @@
14
14
  @submit="$emit('confirm', label)"
15
15
  @cancel="$emit('cancel')"
16
16
  >
17
- <div>
17
+ <div class="bk-reusable-dialog-form">
18
+ <InfoBox
19
+ :text="
20
+ $t(
21
+ 'libraryDialogReusableInfo',
22
+ 'The library item will be available for placement on other pages once this page has been published.',
23
+ )
24
+ "
25
+ />
18
26
  <label for="reusable_label" class="bk-form-label">{{
19
27
  $t('libraryDialogDescriptionLabel', 'Description')
20
28
  }}</label>
@@ -44,8 +52,7 @@
44
52
 
45
53
  <script lang="ts" setup>
46
54
  import { ref, useBlokkli, onMounted } from '#imports'
47
-
48
- import { DialogModal } from '#blokkli/components'
55
+ import { DialogModal, InfoBox } from '#blokkli/components'
49
56
  import { realBackgroundColor } from '#blokkli/helpers'
50
57
 
51
58
  defineEmits<{
@@ -41,4 +41,6 @@ const props = defineProps<{
41
41
  const selected = defineModel<string[]>()
42
42
 
43
43
  const isSelected = computed(() => selected.value?.includes(props.mediaId))
44
+
45
+ // @TODO: Shift-click to select all media items inbetween.
44
46
  </script>
@@ -29,7 +29,10 @@ const gl = animation.gl()
29
29
 
30
30
  const enabled = computed(
31
31
  () =>
32
- !selection.editableActive.value && state.editMode.value === 'editing' && gl,
32
+ !selection.editableActive.value &&
33
+ (state.editMode.value === 'editing' ||
34
+ state.editMode.value === 'translating') &&
35
+ gl,
33
36
  )
34
37
 
35
38
  const shouldRender = ref(false)
@@ -3,7 +3,8 @@
3
3
  v-if="availableOptions.length"
4
4
  class="bk-blokkli-item-options"
5
5
  @pointerup="onPointerUp"
6
- @mouseleave="stopChangingOptions"
6
+ @mouseleave="onMouseLeave"
7
+ @mouseenter="onMouseEnter"
7
8
  >
8
9
  <OptionsFormItem
9
10
  v-for="plugin in singleVisibleOptions"
@@ -102,6 +103,18 @@ const props = defineProps<{
102
103
  }>()
103
104
 
104
105
  let pointerTimeout: null | number = null
106
+ let mouseLeaveTimeout: null | number = null
107
+
108
+ function onMouseLeave() {
109
+ onMouseEnter()
110
+ mouseLeaveTimeout = window.setTimeout(stopChangingOptions, 500)
111
+ }
112
+
113
+ function onMouseEnter() {
114
+ if (mouseLeaveTimeout) {
115
+ window.clearTimeout(mouseLeaveTimeout)
116
+ }
117
+ }
105
118
 
106
119
  function onPointerUp(e: PointerEvent) {
107
120
  if (pointerTimeout) {
@@ -4,6 +4,7 @@
4
4
  :title="$t('previewNewWindow', 'Preview (new window)')"
5
5
  region="after-menu"
6
6
  icon="open_in_new"
7
+ :disabled="!state.canEdit.value"
7
8
  :tour-text="
8
9
  $t(
9
10
  'previewNewWindowTourText',
@@ -25,7 +26,7 @@ defineBlokkliFeature({
25
26
  description: 'Provides a button to open a preview in a new window.',
26
27
  })
27
28
 
28
- const { $t } = useBlokkli()
29
+ const { $t, state } = useBlokkli()
29
30
 
30
31
  const route = useRoute()
31
32
 
@@ -3,6 +3,7 @@
3
3
  v-if="!ui.isMobile.value"
4
4
  id="preview_with_smartphone"
5
5
  :title="$t('previewWithSmartphone', 'Preview (with smartphone)')"
6
+ :disabled="!state.canEdit.value"
6
7
  :tour-text="
7
8
  $t(
8
9
  'previewWithSmartphoneTourText',
@@ -54,7 +55,7 @@ const { adapter } = defineBlokkliFeature({
54
55
  viewports: ['desktop'],
55
56
  })
56
57
 
57
- const { $t, ui } = useBlokkli()
58
+ const { $t, ui, state } = useBlokkli()
58
59
 
59
60
  const qrCodeVisible = ref(false)
60
61
  const previewGrantUrl = ref<string | undefined | null>('')
@@ -27,6 +27,8 @@ const { adapter, settings } = defineBlokkliFeature({
27
27
  closeAfterPublish: {
28
28
  type: 'checkbox',
29
29
  label: 'Close editor after publishing',
30
+ description:
31
+ 'Immediately closes the editor after successfully publishing or saving.',
30
32
  default: true,
31
33
  group: 'behavior',
32
34
  },
@@ -4,6 +4,7 @@
4
4
  v-slot="{ width, height, isDetached }"
5
5
  :title="$t('responsivePreviewTitle', 'Responsive Preview')"
6
6
  :tour-text="tourText"
7
+ :disabled="!state.canEdit.value"
7
8
  :min-width="375"
8
9
  :min-height="375"
9
10
  :size="size"
@@ -83,7 +84,7 @@ defineBlokkliFeature({
83
84
  'Provides a responsive preview of the current edit state in an iframe.',
84
85
  })
85
86
 
86
- const { $t, storage } = useBlokkli()
87
+ const { $t, storage, state } = useBlokkli()
87
88
 
88
89
  const selectedViewportId = storage.use('mobile-preview:viewport', 'iphone-se')
89
90
  const isRotated = storage.use('mobile-preview:rotated', false)