@blokkli/editor 1.1.3 → 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 (67) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +1693 -41
  3. package/dist/runtime/adapter/drupal/graphql/base.graphql +40 -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 +44 -18
  7. package/dist/runtime/adapter/index.d.ts +15 -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/DraggingOverlay/index.vue +20 -6
  24. package/dist/runtime/components/Edit/Features/EditForm/Frame/index.vue +8 -1
  25. package/dist/runtime/components/Edit/Features/EditableField/index.vue +11 -5
  26. package/dist/runtime/components/Edit/Features/EntityTitle/index.vue +1 -0
  27. package/dist/runtime/components/Edit/Features/History/index.vue +3 -1
  28. package/dist/runtime/components/Edit/Features/ImportExisting/index.vue +5 -2
  29. package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +10 -3
  30. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/Item.vue +46 -0
  31. package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +66 -34
  32. package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +4 -1
  33. package/dist/runtime/components/Edit/Features/Options/Form/index.vue +14 -1
  34. package/dist/runtime/components/Edit/Features/Preview/index.vue +2 -1
  35. package/dist/runtime/components/Edit/Features/PreviewGrant/index.vue +2 -1
  36. package/dist/runtime/components/Edit/Features/Publish/index.vue +2 -0
  37. package/dist/runtime/components/Edit/Features/ResponsivePreview/index.vue +2 -1
  38. package/dist/runtime/components/Edit/Features/Selection/Overlay/fragment.glsl +78 -44
  39. package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +8 -8
  40. package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +6 -1
  41. package/dist/runtime/components/Edit/Features/Settings/Dialog/FeatureSetting/index.vue +23 -2
  42. package/dist/runtime/components/Edit/Features/Settings/Dialog/index.vue +71 -38
  43. package/dist/runtime/components/Edit/Features/Settings/index.vue +4 -0
  44. package/dist/runtime/components/Edit/Features/Transform/index.vue +5 -1
  45. package/dist/runtime/components/Edit/Features/Translations/index.vue +24 -2
  46. package/dist/runtime/components/Edit/Features/index.vue +4 -0
  47. package/dist/runtime/components/Edit/InfoBox/index.vue +14 -0
  48. package/dist/runtime/components/Edit/Messages/index.vue +10 -12
  49. package/dist/runtime/components/Edit/PreviewProvider.vue +9 -2
  50. package/dist/runtime/components/Edit/Sortli/index.vue +6 -1
  51. package/dist/runtime/components/Edit/index.d.ts +2 -1
  52. package/dist/runtime/components/Edit/index.js +3 -1
  53. package/dist/runtime/constants/index.d.ts +1 -1
  54. package/dist/runtime/constants/index.js +1 -0
  55. package/dist/runtime/css/output.css +1 -1
  56. package/dist/runtime/helpers/animationProvider.js +2 -1
  57. package/dist/runtime/helpers/featuresProvider.d.ts +7 -14
  58. package/dist/runtime/helpers/featuresProvider.js +29 -1
  59. package/dist/runtime/helpers/stateProvider.d.ts +1 -0
  60. package/dist/runtime/helpers/stateProvider.js +23 -4
  61. package/dist/runtime/helpers/uiProvider.d.ts +5 -1
  62. package/dist/runtime/helpers/uiProvider.js +10 -2
  63. package/dist/runtime/icons/diff.svg +1 -0
  64. package/dist/runtime/icons/info.svg +1 -0
  65. package/dist/runtime/types/generatedModuleTypes.d.ts +4 -4
  66. package/dist/runtime/types/index.d.ts +59 -1
  67. 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
 
@@ -90,7 +90,9 @@ type FilteredItemType<T extends DraggableItem> = T extends {
90
90
  ? { itemType: 'existing'; items: T[] }
91
91
  : T extends { itemType: 'existing_structure' }
92
92
  ? { itemType: 'existing_structure'; items: T[] }
93
- : { itemType: T['itemType']; item: T }
93
+ : T extends { itemType: 'media_library' }
94
+ ? { itemType: 'media_library'; items: T[] }
95
+ : { itemType: T['itemType']; item: T }
94
96
 
95
97
  function filterItemType<T extends DraggableItem>(
96
98
  items: T[],
@@ -105,7 +107,11 @@ function filterItemType<T extends DraggableItem>(
105
107
 
106
108
  const itemType = items[0].itemType
107
109
 
108
- if (itemType === 'existing' || itemType === 'existing_structure') {
110
+ if (
111
+ itemType === 'existing' ||
112
+ itemType === 'existing_structure' ||
113
+ itemType === 'media_library'
114
+ ) {
109
115
  return { itemType, items } as any
110
116
  }
111
117
 
@@ -211,16 +217,24 @@ const onDropClipboardItem = async (
211
217
  }
212
218
 
213
219
  const onDropMediaLibraryItem = async (
214
- item: DraggableMediaLibraryItem,
220
+ items: DraggableMediaLibraryItem[],
215
221
  host: DraggableHostData,
216
222
  afterUuid?: string,
217
223
  ) => {
218
- if (adapter.mediaLibraryAddBlock) {
224
+ if (adapter.mediaLibraryAddBlock && items.length === 1) {
219
225
  await state.mutateWithLoadingState(() =>
220
226
  adapter.mediaLibraryAddBlock({
221
227
  preceedingUuid: afterUuid,
222
228
  host,
223
- item,
229
+ item: items[0],
230
+ }),
231
+ )
232
+ } else if (adapter.mediaLibraryAddBlocks && items.length > 1) {
233
+ await state.mutateWithLoadingState(() =>
234
+ adapter.mediaLibraryAddBlocks({
235
+ preceedingUuid: afterUuid,
236
+ host,
237
+ items,
224
238
  }),
225
239
  )
226
240
  }
@@ -279,7 +293,7 @@ const onDrop = (e: DropTargetEvent) => {
279
293
  } else if (typed.itemType === 'action') {
280
294
  onDropAction(typed.item, host, e.field, afterUuid)
281
295
  } else if (typed.itemType === 'media_library') {
282
- await onDropMediaLibraryItem(typed.item, host, afterUuid)
296
+ await onDropMediaLibraryItem(typed.items, host, afterUuid)
283
297
  }
284
298
 
285
299
  eventBus.emit('dragging:end')
@@ -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<{
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <div
3
+ :key="mediaId"
4
+ class="bk-media-library-items-item"
5
+ :class="{ 'bk-is-selected': isSelected }"
6
+ :data-sortli-id="'media_library_' + mediaId"
7
+ data-element-type="media_library"
8
+ :data-item-bundle="targetBundles[0]"
9
+ :data-media-id="mediaId"
10
+ :data-media-bundle="mediaBundle"
11
+ >
12
+ <div class="bk-media-library-items-item-box">
13
+ <label @click.stop>
14
+ <input v-model="selected" type="checkbox" :value="mediaId" />
15
+ </label>
16
+ <div class="bk-media-library-items-item-image">
17
+ <img :src="thumbnail" />
18
+ </div>
19
+ </div>
20
+ <div class="bk-media-library-items-item-text">
21
+ <h3>{{ label }}</h3>
22
+ <p>{{ context }}</p>
23
+ </div>
24
+ </div>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import type { BlokkliIcon } from '#blokkli/icons'
29
+ import { computed } from '#imports'
30
+
31
+ const props = defineProps<{
32
+ mediaId: string
33
+ label: string
34
+ context: string
35
+ targetBundles: string[]
36
+ thumbnail?: string
37
+ icon?: BlokkliIcon
38
+ mediaBundle?: string
39
+ }>()
40
+
41
+ const selected = defineModel<string[]>()
42
+
43
+ const isSelected = computed(() => selected.value?.includes(props.mediaId))
44
+
45
+ // @TODO: Shift-click to select all media items inbetween.
46
+ </script>