quasar-ui-danx 0.0.11 → 0.0.13

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 (84) hide show
  1. package/dist/index.css +5 -0
  2. package/dist/index.min.css +5 -0
  3. package/dist/index.rtl.css +5 -0
  4. package/dist/index.rtl.min.css +5 -0
  5. package/package.json +6 -1
  6. package/src/components/ActionTable/ActionTable.vue +49 -41
  7. package/src/components/ActionTable/BatchActionMenu.vue +20 -20
  8. package/src/components/ActionTable/EmptyTableState.vue +5 -5
  9. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +11 -11
  10. package/src/components/ActionTable/Filters/FilterGroupItem.vue +7 -7
  11. package/src/components/ActionTable/Filters/FilterGroupList.vue +29 -29
  12. package/src/components/ActionTable/Filters/FilterListToggle.vue +15 -15
  13. package/src/components/ActionTable/Filters/FilterableField.vue +82 -80
  14. package/src/components/ActionTable/Filters/index.ts +5 -0
  15. package/src/components/ActionTable/Form/Fields/BooleanField.vue +13 -13
  16. package/src/components/ActionTable/Form/Fields/ConfirmPasswordField.vue +11 -11
  17. package/src/components/ActionTable/Form/Fields/DateField.vue +13 -13
  18. package/src/components/ActionTable/Form/Fields/DateRangeField.vue +25 -25
  19. package/src/components/ActionTable/Form/Fields/DateTimeField.vue +21 -21
  20. package/src/components/ActionTable/Form/Fields/DateTimePicker.vue +23 -23
  21. package/src/components/ActionTable/Form/Fields/FileUploadButton.vue +31 -31
  22. package/src/components/ActionTable/Form/Fields/InlineDateTimeField.vue +19 -19
  23. package/src/components/ActionTable/Form/Fields/IntegerField.vue +7 -7
  24. package/src/components/ActionTable/Form/Fields/LabelValueBlock.vue +22 -0
  25. package/src/components/ActionTable/Form/Fields/LabeledInput.vue +19 -19
  26. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +40 -40
  27. package/src/components/ActionTable/Form/Fields/MultiKeywordField.vue +23 -23
  28. package/src/components/ActionTable/Form/Fields/NewPasswordField.vue +10 -10
  29. package/src/components/ActionTable/Form/Fields/NumberField.vue +29 -29
  30. package/src/components/ActionTable/Form/Fields/NumberRangeField.vue +33 -33
  31. package/src/components/ActionTable/Form/Fields/SelectDrawer.vue +36 -36
  32. package/src/components/ActionTable/Form/Fields/SelectField.vue +66 -66
  33. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +23 -23
  34. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +32 -32
  35. package/src/components/ActionTable/Form/Fields/TextField.vue +36 -36
  36. package/src/components/ActionTable/Form/Fields/WysiwygField.vue +16 -16
  37. package/src/components/ActionTable/Form/Fields/index.ts +23 -23
  38. package/src/components/ActionTable/Form/RenderedForm.vue +27 -25
  39. package/src/components/ActionTable/Form/index.ts +2 -0
  40. package/src/components/ActionTable/TableSummaryRow.vue +33 -33
  41. package/src/components/ActionTable/index.ts +8 -13
  42. package/src/components/ActionTable/listActions.ts +340 -339
  43. package/src/components/ActionTable/listHelpers.ts +74 -0
  44. package/src/components/ActionTable/tableColumns.ts +56 -56
  45. package/src/components/DragAndDrop/HandleDraggable.vue +29 -29
  46. package/src/components/DragAndDrop/ListItemDraggable.vue +10 -10
  47. package/src/components/DragAndDrop/index.ts +0 -1
  48. package/src/components/DragAndDrop/listDragAndDrop.ts +1 -1
  49. package/src/components/Utility/CollapsableSidebar.vue +35 -35
  50. package/src/components/Utility/ContentDrawer.vue +20 -20
  51. package/src/components/Utility/Dialogs/ConfirmDialog.vue +55 -55
  52. package/src/components/Utility/Dialogs/FullScreenDialog.vue +18 -18
  53. package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +105 -0
  54. package/src/components/Utility/Dialogs/InfoDialog.vue +10 -10
  55. package/src/components/Utility/Dialogs/InputDialog.vue +13 -13
  56. package/src/components/Utility/ImagePreview.vue +192 -0
  57. package/src/components/Utility/Popover/PopoverMenu.vue +64 -0
  58. package/src/components/Utility/Transitions/StaggeredListTransition.vue +15 -15
  59. package/src/components/Utility/index.ts +11 -9
  60. package/src/components/index.ts +1 -1
  61. package/src/helpers/FileUpload.ts +274 -273
  62. package/src/helpers/compatibility.ts +45 -45
  63. package/src/helpers/date.ts +2 -2
  64. package/src/helpers/download.ts +166 -158
  65. package/src/helpers/downloadPdf.ts +48 -48
  66. package/src/helpers/files.ts +42 -42
  67. package/src/helpers/index.ts +2 -0
  68. package/src/helpers/multiFileUpload.ts +56 -56
  69. package/src/helpers/singleFileUpload.ts +49 -49
  70. package/src/index.esm.js +3 -4
  71. package/src/svg/FilterIcon.svg +7 -0
  72. package/src/svg/ImageIcon.svg +30 -0
  73. package/src/svg/PdfIcon.svg +21 -0
  74. package/src/svg/PercentIcon.svg +13 -0
  75. package/src/svg/TrashIcon.svg +15 -0
  76. package/src/svg/XIcon.svg +18 -0
  77. package/src/svg/index.ts +8 -0
  78. package/src/vendor/tinymce-config.ts +1 -0
  79. package/src/vue-plugin.js +7 -4
  80. package/tsconfig.json +18 -14
  81. package/src/components/ActionTable/tableHelpers.ts +0 -83
  82. package/src/components/DragAndDrop/Icons/index.ts +0 -2
  83. /package/src/{components/DragAndDrop/Icons → svg}/DragHandleDotsIcon.svg +0 -0
  84. /package/src/{components/DragAndDrop/Icons → svg}/DragHandleIcon.svg +0 -0
@@ -1,95 +1,95 @@
1
1
  <template>
2
- <QDialog
3
- :full-height="fullHeight"
4
- :full-width="fullWidth"
5
- :model-value="!!modelValue"
6
- :no-backdrop-dismiss="!backdropDismiss"
7
- :maximized="maximized"
8
- @update:model-value="onClose"
2
+ <q-dialog
3
+ :full-height="fullHeight"
4
+ :full-width="fullWidth"
5
+ :model-value="!!modelValue"
6
+ :no-backdrop-dismiss="!backdropDismiss"
7
+ :maximized="maximized"
8
+ @update:model-value="onClose"
9
9
  >
10
- <QCard class="flex flex-col flex-nowrap">
11
- <QCardSection
12
- v-if="title || $slots.title"
13
- class="pl-6 pr-10 border-b border-gray-medium"
10
+ <q-card class="flex flex-col flex-nowrap">
11
+ <q-card-section
12
+ v-if="title || $slots.title"
13
+ class="pl-6 pr-10 border-b border-gray-medium"
14
14
  >
15
15
  <h3
16
- class="font-normal flex items-center"
17
- :class="titleClass"
16
+ class="font-normal flex items-center"
17
+ :class="titleClass"
18
18
  >
19
19
  <slot name="title">{{ title }}</slot>
20
20
  </h3>
21
21
  <div
22
- v-if="subtitle"
23
- class="mt-1 text-sm"
22
+ v-if="subtitle"
23
+ class="mt-1 text-sm"
24
24
  >{{ subtitle }}
25
25
  </div>
26
- </QCardSection>
27
- <QCardSection v-if="$slots.toolbar">
26
+ </q-card-section>
27
+ <q-card-section v-if="$slots.toolbar">
28
28
  <slot name="toolbar" />
29
- </QCardSection>
30
- <QCardSection
31
- v-if="content || $slots.default"
32
- class="px-6 bg-neutral-plus-7 flex-grow max-h-full overflow-y-auto"
33
- :class="contentClass"
29
+ </q-card-section>
30
+ <q-card-section
31
+ v-if="content || $slots.default"
32
+ class="px-6 bg-neutral-plus-7 flex-grow max-h-full overflow-y-auto"
33
+ :class="contentClass"
34
34
  >
35
35
  <slot>{{ content }}</slot>
36
- </QCardSection>
36
+ </q-card-section>
37
37
  <div class="flex px-6 py-4 border-t border-gray-medium">
38
38
  <div class="flex-grow">
39
- <QBtn
40
- :label="cancelText"
41
- class="action-btn btn-white-gray"
42
- @click="onClose"
39
+ <q-btn
40
+ :label="cancelText"
41
+ class="action-btn btn-white-gray"
42
+ @click="onClose"
43
43
  >
44
44
  <slot name="cancel-text" />
45
- </QBtn>
45
+ </q-btn>
46
46
  </div>
47
47
  <slot name="actions" />
48
48
  <div v-if="!hideConfirm">
49
- <QBtn
50
- :label="$slots['confirm-text'] ? '' : confirmText"
51
- class="action-btn ml-4"
52
- :class="confirmClass"
53
- :loading="isSaving"
54
- :disable="disabled"
55
- data-testid="confirm-button"
56
- @click="onConfirm"
49
+ <q-btn
50
+ :label="$slots['confirm-text'] ? '' : confirmText"
51
+ class="action-btn ml-4"
52
+ :class="confirmClass"
53
+ :loading="isSaving"
54
+ :disable="disabled"
55
+ data-testid="confirm-button"
56
+ @click="onConfirm"
57
57
  >
58
58
  <slot name="confirm-text" />
59
- </QBtn>
59
+ </q-btn>
60
60
  </div>
61
61
  </div>
62
62
  <a
63
- class="absolute top-0 right-0 p-4 text-black"
64
- @click="onClose"
63
+ class="absolute top-0 right-0 p-4 text-black"
64
+ @click="onClose"
65
65
  >
66
66
  <CloseIcon class="w-5" />
67
67
  </a>
68
- </QCard>
69
- </QDialog>
68
+ </q-card>
69
+ </q-dialog>
70
70
  </template>
71
71
 
72
72
  <script setup>
73
- import { XIcon as CloseIcon } from "@heroicons/vue/outline";
73
+ import { XIcon as CloseIcon } from '@heroicons/vue/outline';
74
74
 
75
- const emit = defineEmits(["update:model-value", "confirm", "close"]);
75
+ const emit = defineEmits(['update:model-value', 'confirm', 'close']);
76
76
  const props = defineProps({
77
77
  modelValue: { type: [String, Boolean, Object], default: true },
78
78
  title: {
79
79
  type: String,
80
- default: ""
80
+ default: ''
81
81
  },
82
82
  titleClass: {
83
83
  type: String,
84
- default: ""
84
+ default: ''
85
85
  },
86
86
  subtitle: {
87
87
  type: String,
88
- default: ""
88
+ default: ''
89
89
  },
90
90
  content: {
91
91
  type: String,
92
- default: ""
92
+ default: ''
93
93
  },
94
94
  backdropDismiss: Boolean,
95
95
  maximized: Boolean,
@@ -101,32 +101,32 @@ const props = defineProps({
101
101
  hideConfirm: Boolean,
102
102
  confirmText: {
103
103
  type: String,
104
- default: "Confirm"
104
+ default: 'Confirm'
105
105
  },
106
106
  cancelText: {
107
107
  type: String,
108
- default: "Cancel"
108
+ default: 'Cancel'
109
109
  },
110
110
  confirmClass: {
111
111
  type: String,
112
- default: "bg-blue-base text-white"
112
+ default: 'bg-blue-base text-white'
113
113
  },
114
114
  contentClass: {
115
115
  type: String,
116
- default: ""
116
+ default: ''
117
117
  }
118
118
  });
119
119
 
120
120
  function onConfirm() {
121
- emit("confirm");
121
+ emit('confirm');
122
122
 
123
123
  if (props.closeOnConfirm) {
124
- emit("close");
124
+ emit('close');
125
125
  }
126
126
  }
127
127
 
128
128
  function onClose() {
129
- emit("update:model-value", false);
130
- emit("close");
129
+ emit('update:model-value', false);
130
+ emit('close');
131
131
  }
132
132
  </script>
@@ -1,29 +1,29 @@
1
1
  <template>
2
- <QDialog
3
- :model-value="modelValue"
4
- maximized
5
- transition-show="slide-up"
6
- transition-hide="slide-down"
7
- @update:model-value="onClose"
2
+ <q-dialog
3
+ :model-value="modelValue"
4
+ maximized
5
+ transition-show="slide-up"
6
+ transition-hide="slide-down"
7
+ @update:model-value="onClose"
8
8
  >
9
9
  <div class="flex justify-center min-w-xs" :class="computedClass">
10
10
  <div
11
- v-if="closeable"
12
- v-close-popup
13
- class="p-4 m-4 absolute-top-right top right cursor-pointer"
11
+ v-if="closeable"
12
+ v-close-popup
13
+ class="p-4 m-4 absolute-top-right top right cursor-pointer"
14
14
  >
15
15
  <XIcon class="w-5 h-5" />
16
16
  </div>
17
17
  <slot />
18
18
  </div>
19
- </QDialog>
19
+ </q-dialog>
20
20
  </template>
21
21
 
22
22
  <script setup>
23
- import { XIcon } from "src/svg";
24
- import { computed } from "vue";
23
+ import { XIcon } from '@ui/svg';
24
+ import { computed } from 'vue';
25
25
 
26
- const emit = defineEmits(["update:model-value", "close"]);
26
+ const emit = defineEmits(['update:model-value', 'close']);
27
27
  const props = defineProps({
28
28
  modelValue: Boolean,
29
29
  center: Boolean,
@@ -33,14 +33,14 @@ const props = defineProps({
33
33
 
34
34
  let computedClass = computed(() => {
35
35
  return {
36
- "bg-blue-base text-white": props.blue,
37
- "bg-white text-gray-base": !props.blue,
38
- "items-center": props.center
36
+ 'bg-blue-base text-white': props.blue,
37
+ 'bg-white text-gray-base': !props.blue,
38
+ 'items-center': props.center
39
39
  };
40
40
  });
41
41
 
42
42
  function onClose() {
43
- emit("update:model-value", false);
44
- emit("close");
43
+ emit('update:model-value', false);
44
+ emit('close');
45
45
  }
46
46
  </script>
@@ -0,0 +1,105 @@
1
+ <template>
2
+ <q-dialog
3
+ :model-value="true"
4
+ maximized
5
+ @update:model-value="$emit('close')"
6
+ @keyup.left="carousel.previous()"
7
+ @keyup.right="carousel.next()"
8
+ >
9
+ <div class="absolute top-0 left-0 w-full h-full">
10
+ <q-carousel
11
+ ref="carousel"
12
+ v-model="currentSlide"
13
+ height="100%"
14
+ swipeable
15
+ animated
16
+ :thumbnails="files.length > 1"
17
+ infinite
18
+ class="carousel"
19
+ >
20
+ <q-carousel-slide
21
+ v-for="file in files"
22
+ :key="'file-' + file.id"
23
+ :name="file.id"
24
+ :img-src="getThumbUrl(file)"
25
+ >
26
+ <div class="slide-image">
27
+ <template v-if="isVideo(file)">
28
+ <video
29
+ class="max-h-full w-full"
30
+ controls
31
+ >
32
+ <source
33
+ :src="file.url + '#t=0.1'"
34
+ :type="file.mime"
35
+ />
36
+ </video>
37
+ </template>
38
+ <img v-else :alt="file.filename" :src="file.url" />
39
+ </div>
40
+ </q-carousel-slide>
41
+ </q-carousel>
42
+ <CloseIcon
43
+ class="absolute top-4 right-4 cursor-pointer text-white w-8 h-8"
44
+ @click="$emit('close')"
45
+ />
46
+ </div>
47
+ </q-dialog>
48
+ </template>
49
+ <script setup>
50
+ import { XIcon as CloseIcon } from '@ui/svg';
51
+ import { ref } from 'vue';
52
+
53
+ defineEmits(['close']);
54
+ const props = defineProps({
55
+ files: {
56
+ type: Array,
57
+ default: () => []
58
+ },
59
+ defaultSlide: {
60
+ type: String,
61
+ default: ''
62
+ }
63
+ });
64
+
65
+ const carousel = ref(null);
66
+ const currentSlide = ref(props.defaultSlide);
67
+ function isVideo(file) {
68
+ return file.mime?.startsWith('video');
69
+ }
70
+ function getThumbUrl(file) {
71
+ if (file.thumb) {
72
+ return file.thumb.url;
73
+ } else if (isVideo(file)) {
74
+ // Base64 encode a PlayIcon for the placeholder image
75
+ return `data:image/svg+xml;base64,${btoa(
76
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/></svg>`
77
+ )}`;
78
+ } else {
79
+ return file.url;
80
+ }
81
+ }
82
+ </script>
83
+ <style scoped lang="scss">
84
+ .slide-image {
85
+ width: 100%;
86
+ height: 100%;
87
+ background: black;
88
+ display: flex;
89
+ justify-content: center;
90
+ align-items: center;
91
+
92
+ img {
93
+ max-height: 100%;
94
+ max-width: 100%;
95
+ object-fit: contain;
96
+ }
97
+ }
98
+
99
+ .carousel {
100
+ :deep(.q-carousel__navigation--bottom) {
101
+ position: relative;
102
+ bottom: 8em;
103
+ }
104
+ }
105
+ </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <QDialog
2
+ <q-dialog
3
3
  :full-height="fullHeight"
4
4
  :full-width="fullWidth"
5
5
  :model-value="!!modelValue"
@@ -7,8 +7,8 @@
7
7
  :maximized="maximized"
8
8
  @update:model-value="onClose"
9
9
  >
10
- <QCard class="flex flex-col flex-nowrap">
11
- <QCardSection
10
+ <q-card class="flex flex-col flex-nowrap">
11
+ <q-card-section
12
12
  v-if="title || $slots.title"
13
13
  class="pl-6 pr-10 border-b border-gray-medium"
14
14
  >
@@ -23,24 +23,24 @@
23
23
  class="mt-1 text-sm"
24
24
  >{{ subtitle }}
25
25
  </div>
26
- </QCardSection>
27
- <QCardSection
26
+ </q-card-section>
27
+ <q-card-section
28
28
  v-if="content || $slots.default"
29
29
  class="px-6 bg-neutral-plus-7 flex-grow max-h-full overflow-y-auto"
30
30
  >
31
31
  <slot>{{ content }}</slot>
32
- </QCardSection>
32
+ </q-card-section>
33
33
  <div
34
34
  class="flex items-center justify-center px-6 py-4 border-t border-gray-medium"
35
35
  >
36
36
  <div class="flex-grow text-right">
37
- <QBtn
37
+ <q-btn
38
38
  :label="doneText"
39
39
  class="action-btn btn-white-gray"
40
40
  @click="onClose"
41
41
  >
42
42
  <slot name="done-text" />
43
- </QBtn>
43
+ </q-btn>
44
44
  </div>
45
45
  </div>
46
46
  <a
@@ -49,8 +49,8 @@
49
49
  >
50
50
  <CloseIcon class="w-5" />
51
51
  </a>
52
- </QCard>
53
- </QDialog>
52
+ </q-card>
53
+ </q-dialog>
54
54
  </template>
55
55
 
56
56
  <script setup>
@@ -1,33 +1,33 @@
1
1
  <template>
2
2
  <ConfirmDialog
3
- v-bind="$props"
4
- @confirm="$emit('confirm', newInput)"
5
- @close="$emit('close', $event)"
3
+ v-bind="$props"
4
+ @confirm="$emit('confirm', newInput)"
5
+ @close="$emit('close', $event)"
6
6
  >
7
7
  <slot>
8
- <QInput
9
- v-model="newInput"
10
- type="number"
11
- class="w-full"
12
- @input="$emit('update:input', $event)"
8
+ <q-input
9
+ v-model="newInput"
10
+ type="number"
11
+ class="w-full"
12
+ @input="$emit('update:input', $event)"
13
13
  />
14
14
  </slot>
15
15
  </ConfirmDialog>
16
16
  </template>
17
17
  <script setup>
18
- import ConfirmDialog from "danx/src/components/Utility/Dialogs/ConfirmDialog";
19
- import { ref } from "vue";
18
+ import { ref } from 'vue';
19
+ import ConfirmDialog from './ConfirmDialog';
20
20
 
21
- defineEmits(["confirm", "close", "update:input"]);
21
+ defineEmits(['confirm', 'close', 'update:input']);
22
22
  const props = defineProps({
23
23
  ...ConfirmDialog.props,
24
24
  title: {
25
25
  type: String,
26
- default: "Enter Value"
26
+ default: 'Enter Value'
27
27
  },
28
28
  input: {
29
29
  type: [Number, String],
30
- default: ""
30
+ default: ''
31
31
  }
32
32
  });
33
33
 
@@ -0,0 +1,192 @@
1
+ <template>
2
+ <div class="relative flex justify-center bg-neutral-plus-7" :class="{'rounded-2xl': !square}">
3
+ <template v-if="computedImage">
4
+ <div
5
+ class="grow h-full overflow-hidden"
6
+ :class="{'rounded-2xl': !square}"
7
+ @click="showPreview = true"
8
+ >
9
+ <div
10
+ v-if="isVideo"
11
+ class="relative max-h-full max-w-full w-full flex justify-center"
12
+ >
13
+ <video
14
+ class="max-h-full"
15
+ preload="auto"
16
+ >
17
+ <source
18
+ :src="previewUrl + '#t=0.1'"
19
+ :type="mimeType"
20
+ />
21
+ </video>
22
+ <button class="play-button text-blue-lighter">
23
+ <PlayIcon class="w-16" />
24
+ </button>
25
+ </div>
26
+ <div
27
+ v-if="isPdf && !thumbUrl"
28
+ class="flex items-center justify-center h-full"
29
+ >
30
+ <PdfIcon class="w-24" />
31
+ </div>
32
+ <q-img
33
+ v-else
34
+ fit="scale-down"
35
+ class="non-selectable max-h-full max-w-full h-full"
36
+ :src="(thumbUrl || previewUrl) + '#t=0.1'"
37
+ preload="auto"
38
+ data-testid="previewed-image"
39
+ data-dusk="previewed-image"
40
+ />
41
+ </div>
42
+ <div
43
+ v-if="$slots['action-button']"
44
+ class="action-button"
45
+ >
46
+ <slot name="action-button" />
47
+ </div>
48
+ <div
49
+ v-if="image && image.progress !== undefined"
50
+ class="absolute-bottom w-full"
51
+ >
52
+ <q-linear-progress
53
+ :value="image.progress"
54
+ size="15px"
55
+ color="green-base"
56
+ stripe
57
+ />
58
+ </div>
59
+ </template>
60
+ <template v-else>
61
+ <slot name="missing">
62
+ <component
63
+ :is="missingIcon"
64
+ class="w-full h-full p-2 text-gray-medium"
65
+ />
66
+ </slot>
67
+ </template>
68
+
69
+ <div class="absolute top-1 right-1 flex items-center justify-between space-x-1">
70
+ <q-btn
71
+ v-if="downloadable && computedImage?.url"
72
+ size="sm"
73
+ class="!p-1 opacity-70 hover:opacity-100"
74
+ :class="downloadButtonClass"
75
+ @click.stop="download(computedImage.url)"
76
+ >
77
+ <DownloadIcon class="w-4 h-5" />
78
+ </q-btn>
79
+
80
+ <q-btn
81
+ v-if="removable"
82
+ size="sm"
83
+ class="bg-red-dark text-white !p-1 opacity-50 hover:opacity-100"
84
+ @click.stop="onRemove"
85
+ >
86
+ <div v-if="isConfirmingRemove" class="font-bold text-[1rem] leading-[1.2rem]">?</div>
87
+ <RemoveIcon v-else class="w-3" />
88
+ </q-btn>
89
+ </div>
90
+
91
+ <FullScreenCarouselDialog
92
+ v-if="showPreview && !disabled"
93
+ :files="relatedFiles || [computedImage]"
94
+ :default-slide="computedImage.id"
95
+ @close="showPreview = false"
96
+ />
97
+ </div>
98
+ </template>
99
+
100
+ <script setup>
101
+ import { DownloadIcon, PlayIcon } from '@heroicons/vue/outline';
102
+ import { FullScreenCarouselDialog } from '@ui/components';
103
+ import { download } from '@ui/helpers';
104
+ import { ImageIcon, PdfIcon, TrashIcon as RemoveIcon } from '@ui/svg';
105
+ import { computed, ref } from 'vue';
106
+
107
+ const emit = defineEmits(['remove']);
108
+ const props = defineProps({
109
+ src: {
110
+ type: String,
111
+ default: ''
112
+ },
113
+ image: {
114
+ type: Object,
115
+ default: null
116
+ },
117
+ relatedFiles: {
118
+ type: Array,
119
+ default: null
120
+ },
121
+ missingIcon: {
122
+ type: [Function, Object],
123
+ default: ImageIcon
124
+ },
125
+ downloadButtonClass: {
126
+ type: String,
127
+ default: 'bg-blue-base text-white'
128
+ },
129
+ downloadable: Boolean,
130
+ removable: Boolean,
131
+ disabled: Boolean,
132
+ square: Boolean
133
+ });
134
+
135
+ const showPreview = ref(false);
136
+ const computedImage = computed(() => {
137
+ if (props.image) {
138
+ return props.image;
139
+ } else if (props.src) {
140
+ return {
141
+ id: props.src,
142
+ url: props.src,
143
+ type: 'image/' + props.src.split('.').pop().toLowerCase()
144
+ };
145
+ }
146
+ return null;
147
+ });
148
+ const mimeType = computed(
149
+ () => computedImage.value.type || computedImage.value.mime
150
+ );
151
+ const isVideo = computed(() => mimeType.value.match(/^video\//));
152
+ const isPdf = computed(() => mimeType.value.match(/^application\/pdf/));
153
+ const previewUrl = computed(
154
+ () => computedImage.value.transcodes?.compress?.url || computedImage.value.blobUrl || computedImage.value.url
155
+ );
156
+ const thumbUrl = computed(() => {
157
+ return computedImage.value.transcodes?.thumb?.url;
158
+ });
159
+
160
+ const isConfirmingRemove = ref(false);
161
+ function onRemove() {
162
+ if (!isConfirmingRemove.value) {
163
+ isConfirmingRemove.value = true;
164
+ setTimeout(() => {
165
+ isConfirmingRemove.value = false;
166
+ }, 2000);
167
+ } else {
168
+ emit('remove');
169
+ }
170
+ }
171
+ </script>
172
+
173
+ <style scoped lang="scss">
174
+ .action-button {
175
+ position: absolute;
176
+ bottom: 1.5em;
177
+ right: 1em;
178
+ z-index: 1;
179
+ }
180
+
181
+ .play-button {
182
+ position: absolute;
183
+ top: 0;
184
+ left: 0;
185
+ display: flex;
186
+ justify-content: center;
187
+ align-items: center;
188
+ width: 100%;
189
+ height: 100%;
190
+ pointer-events: none;
191
+ }
192
+ </style>