quasar-ui-danx 0.4.2 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. package/dist/danx.es.js +7127 -6615
  2. package/dist/danx.es.js.map +1 -1
  3. package/dist/danx.umd.js +11 -5
  4. package/dist/danx.umd.js.map +1 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +3 -1
  7. package/src/components/ActionTable/ActionTable.vue +28 -41
  8. package/src/components/ActionTable/Columns/ActionTableColumn.vue +19 -18
  9. package/src/components/ActionTable/Filters/CollapsableFiltersSidebar.vue +6 -6
  10. package/src/components/ActionTable/Filters/{FilterFieldList.vue → FilterList.vue} +26 -26
  11. package/src/components/ActionTable/Filters/FilterableField.vue +28 -31
  12. package/src/components/ActionTable/Filters/index.ts +2 -2
  13. package/src/components/ActionTable/Form/Fields/EditOnClickTextField.vue +71 -0
  14. package/src/components/ActionTable/Form/Fields/FieldLabel.vue +8 -13
  15. package/src/components/ActionTable/Form/Fields/MultiFileField.vue +48 -44
  16. package/src/components/ActionTable/Form/Fields/SelectField.vue +24 -38
  17. package/src/components/ActionTable/Form/Fields/SelectWithChildrenField.vue +28 -33
  18. package/src/components/ActionTable/Form/Fields/SingleFileField.vue +15 -15
  19. package/src/components/ActionTable/Form/Fields/SliderNumberField.vue +45 -0
  20. package/src/components/ActionTable/Form/Fields/TextField.vue +47 -66
  21. package/src/components/ActionTable/Form/Fields/index.ts +2 -0
  22. package/src/components/ActionTable/Form/RenderedForm.vue +50 -9
  23. package/src/components/ActionTable/Form/Utilities/MaxLengthCounter.vue +17 -0
  24. package/src/components/ActionTable/Form/Utilities/index.ts +1 -0
  25. package/src/components/ActionTable/Form/index.ts +1 -0
  26. package/src/components/ActionTable/Layouts/ActionTableLayout.vue +16 -15
  27. package/src/components/ActionTable/Toolbars/ActionToolbar.vue +6 -6
  28. package/src/components/ActionTable/listControls.ts +106 -166
  29. package/src/components/ActionTable/listHelpers.ts +2 -3
  30. package/src/components/ActionTable/tableColumns.ts +3 -27
  31. package/src/components/AuditHistory/AuditHistoryItemValue.vue +26 -26
  32. package/src/components/PanelsDrawer/PanelsDrawer.vue +17 -4
  33. package/src/components/PanelsDrawer/PanelsDrawerPanels.vue +6 -11
  34. package/src/components/PanelsDrawer/PanelsDrawerTabs.vue +20 -20
  35. package/src/components/Utility/Dialogs/ConfirmActionDialog.vue +39 -0
  36. package/src/components/Utility/Dialogs/ConfirmDialog.vue +10 -24
  37. package/src/components/Utility/Dialogs/DialogLayout.vue +10 -28
  38. package/src/components/Utility/Dialogs/FullscreenCarouselDialog.vue +42 -36
  39. package/src/components/Utility/Dialogs/index.ts +1 -0
  40. package/src/components/Utility/Files/FilePreview.vue +76 -73
  41. package/src/components/Utility/Layouts/ContentDrawer.vue +24 -31
  42. package/src/components/Utility/Tools/ActionVnode.vue +3 -3
  43. package/src/components/Utility/Tools/RenderVnode.vue +1 -1
  44. package/src/components/Utility/Transitions/MaxHeightTransition.vue +26 -0
  45. package/src/components/Utility/Transitions/index.ts +1 -0
  46. package/src/config/index.ts +36 -31
  47. package/src/helpers/FileUpload.ts +295 -297
  48. package/src/helpers/FlashMessages.ts +80 -71
  49. package/src/helpers/actions.ts +102 -82
  50. package/src/helpers/download.ts +189 -189
  51. package/src/helpers/downloadPdf.ts +55 -52
  52. package/src/helpers/formats.ts +151 -109
  53. package/src/helpers/index.ts +2 -0
  54. package/src/helpers/multiFileUpload.ts +72 -58
  55. package/src/helpers/objectStore.ts +52 -0
  56. package/src/helpers/request.ts +70 -51
  57. package/src/helpers/routes.ts +29 -0
  58. package/src/helpers/storage.ts +7 -3
  59. package/src/helpers/utils.ts +47 -29
  60. package/src/styles/quasar-reset.scss +16 -1
  61. package/src/styles/themes/danx/dialogs.scss +4 -0
  62. package/src/types/actions.d.ts +43 -0
  63. package/src/types/config.d.ts +15 -0
  64. package/src/types/controls.d.ts +99 -0
  65. package/src/types/dialogs.d.ts +32 -0
  66. package/src/types/fields.d.ts +20 -0
  67. package/src/types/files.d.ts +54 -0
  68. package/src/types/formats.d.ts +4 -0
  69. package/src/{components/ActionTable/Form/form.d.ts → types/forms.d.ts} +6 -0
  70. package/src/types/index.d.ts +12 -0
  71. package/src/types/requests.d.ts +13 -0
  72. package/src/types/shared.d.ts +15 -0
  73. package/src/types/tables.d.ts +27 -0
  74. package/types/index.d.ts +1 -1
  75. /package/src/components/ActionTable/Filters/{FilterFieldItem.vue → FilterItem.vue} +0 -0
@@ -28,37 +28,37 @@
28
28
  </template>
29
29
  </QTabs>
30
30
  </template>
31
- <script setup>
31
+ <script setup lang="ts">
32
32
  import { QTab } from "quasar";
33
+ import { ActionPanel } from "../../types";
33
34
  import { RenderVnode } from "../Utility";
34
35
 
35
36
  defineEmits(["update:model-value"]);
36
- defineProps({
37
- modelValue: {
38
- type: String,
39
- default: "general"
40
- },
41
- panels: {
42
- type: Array,
43
- required: true
44
- }
37
+
38
+ interface Props {
39
+ modelValue?: string | number;
40
+ panels: ActionPanel[];
41
+ }
42
+
43
+ withDefaults(defineProps<Props>(), {
44
+ modelValue: "general"
45
45
  });
46
46
  </script>
47
47
 
48
48
  <style lang="scss" module="cls">
49
49
  .panel-tabs {
50
- @apply p-4 h-auto;
50
+ @apply p-4 h-auto;
51
51
 
52
- :global(.q-tab) {
53
- justify-content: start !important;
52
+ :global(.q-tab) {
53
+ justify-content: start !important;
54
54
 
55
- :global(.q-focus-helper), :global(.q-tab__indicator) {
56
- display: none;
57
- }
55
+ :global(.q-focus-helper), :global(.q-tab__indicator) {
56
+ display: none;
57
+ }
58
58
 
59
- :global(.q-tab__content) {
60
- @apply p-0;
61
- }
62
- }
59
+ :global(.q-tab__content) {
60
+ @apply p-0;
61
+ }
62
+ }
63
63
  }
64
64
  </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <ConfirmDialog
3
+ class="dx-confirm-action-dialog"
4
+ v-bind="props"
5
+ :confirm-text="confirmText || computedConfirmText"
6
+ :title="title || computedTitle"
7
+ :content="content || computedContentText"
8
+ @confirm="$emit('confirm')"
9
+ @close="$emit('close')"
10
+ >
11
+ <template
12
+ v-for="slotName in childSlots"
13
+ #[slotName]
14
+ >
15
+ <slot :name="slotName" />
16
+ </template>
17
+ <slot />
18
+ </ConfirmDialog>
19
+ </template>
20
+
21
+ <script setup lang="ts">
22
+ import { computed } from "vue";
23
+ import { fNameOrCount } from "../../../helpers";
24
+ import { ConfirmActionDialogProps } from "../../../types";
25
+ import { default as ConfirmDialog } from "./ConfirmDialog";
26
+
27
+ defineEmits(["confirm", "close"]);
28
+
29
+ const props = withDefaults(defineProps<ConfirmActionDialogProps>(), {
30
+ message: "Are you sure you want to"
31
+ });
32
+
33
+ const nameLabel = computed(() => fNameOrCount(props.target, props.label || props.action));
34
+ const computedTitle = computed(() => `Confirm ${props.action}`);
35
+ const computedConfirmText = computed(() => `${props.action}`);
36
+ const computedContentText = computed(() => `${props.message} ${props.action.toLowerCase()}${nameLabel.value ? " " + nameLabel.value : ""}?`);
37
+
38
+ const childSlots = computed(() => ["title", "subtitle", "default", "toolbar", "actions"]);
39
+ </script>
@@ -10,6 +10,7 @@
10
10
  >
11
11
  <slot :name="slotName" />
12
12
  </template>
13
+ <slot />
13
14
 
14
15
  <template #actions>
15
16
  <div class="dx-dialog-button-cancel">
@@ -42,37 +43,22 @@
42
43
  </DialogLayout>
43
44
  </template>
44
45
 
45
- <script setup>
46
+ <script setup lang="ts">
46
47
  import { computed } from "vue";
48
+ import { ConfirmDialogProps } from "../../../types";
47
49
  import DialogLayout from "./DialogLayout";
48
50
 
49
51
  const emit = defineEmits(["update:model-value", "confirm", "close"]);
50
- const props = defineProps({
51
- ...DialogLayout.props,
52
- disabled: Boolean,
53
- isSaving: Boolean,
54
- closeOnConfirm: Boolean,
55
- hideConfirm: Boolean,
56
- confirmText: {
57
- type: String,
58
- default: "Confirm"
59
- },
60
- cancelText: {
61
- type: String,
62
- default: "Cancel"
63
- },
64
- confirmClass: {
65
- type: String,
66
- default: ""
67
- },
68
- contentClass: {
69
- type: String,
70
- default: ""
71
- }
52
+
53
+ const props = withDefaults(defineProps<ConfirmDialogProps>(), {
54
+ confirmText: "Confirm",
55
+ cancelText: "Cancel",
56
+ confirmClass: "",
57
+ contentClass: ""
72
58
  });
73
59
 
74
60
  const layoutProps = computed(() => ({ ...props, disabled: undefined }));
75
- const childSlots = computed(() => ["title", "subtitle", "default", "toolbar"]);
61
+ const childSlots = computed(() => ["title", "subtitle", "toolbar"]);
76
62
 
77
63
  function onConfirm() {
78
64
  emit("confirm");
@@ -3,7 +3,7 @@
3
3
  class="dx-dialog"
4
4
  :full-height="fullHeight"
5
5
  :full-width="fullWidth"
6
- :model-value="!!modelValue"
6
+ :model-value="true"
7
7
  :no-backdrop-dismiss="!backdropDismiss"
8
8
  :maximized="maximized"
9
9
  @update:model-value="onClose"
@@ -57,36 +57,18 @@
57
57
  </QDialog>
58
58
  </template>
59
59
 
60
- <script setup>
60
+ <script setup lang="ts">
61
61
  import { XIcon as CloseIcon } from "@heroicons/vue/outline";
62
+ import { DialogLayoutProps } from "../../../types";
62
63
 
63
64
  const emit = defineEmits(["close"]);
64
- defineProps({
65
- modelValue: { type: [String, Boolean, Object], default: true },
66
- title: {
67
- type: String,
68
- default: ""
69
- },
70
- titleClass: {
71
- type: String,
72
- default: ""
73
- },
74
- subtitle: {
75
- type: String,
76
- default: ""
77
- },
78
- content: {
79
- type: String,
80
- default: ""
81
- },
82
- backdropDismiss: Boolean,
83
- maximized: Boolean,
84
- fullWidth: Boolean,
85
- fullHeight: Boolean,
86
- contentClass: {
87
- type: String,
88
- default: ""
89
- }
65
+
66
+ withDefaults(defineProps<DialogLayoutProps>(), {
67
+ title: "",
68
+ titleClass: "",
69
+ subtitle: "",
70
+ content: "",
71
+ contentClass: ""
90
72
  });
91
73
 
92
74
  function onClose() {
@@ -22,6 +22,7 @@
22
22
  :key="'file-' + file.id"
23
23
  :name="file.id"
24
24
  :img-src="getThumbUrl(file)"
25
+ class="bg-black"
25
26
  >
26
27
  <div :class="cls['slide-image']">
27
28
  <template v-if="isVideo(file)">
@@ -30,7 +31,7 @@
30
31
  controls
31
32
  >
32
33
  <source
33
- :src="file.url + '#t=0.1'"
34
+ :src="getPreviewUrl(file) + '#t=0.1'"
34
35
  :type="file.mime"
35
36
  >
36
37
  </video>
@@ -38,7 +39,7 @@
38
39
  <img
39
40
  v-else
40
41
  :alt="file.filename"
41
- :src="file.url"
42
+ :src="getPreviewUrl(file)"
42
43
  >
43
44
  </div>
44
45
  </QCarouselSlide>
@@ -56,54 +57,59 @@ import { XIcon as CloseIcon } from "../../../svg";
56
57
 
57
58
  defineEmits(["close"]);
58
59
  const props = defineProps({
59
- files: {
60
- type: Array,
61
- default: () => []
62
- },
63
- defaultSlide: {
64
- type: String,
65
- default: ""
66
- }
60
+ files: {
61
+ type: Array,
62
+ default: () => []
63
+ },
64
+ defaultSlide: {
65
+ type: String,
66
+ default: ""
67
+ }
67
68
  });
68
69
 
69
70
  const carousel = ref(null);
70
71
  const currentSlide = ref(props.defaultSlide);
71
72
  function isVideo(file) {
72
- return file.mime?.startsWith("video");
73
+ return file.mime?.startsWith("video");
73
74
  }
75
+
76
+ function getPreviewUrl(file) {
77
+ return file.transcodes?.compress?.url || file.blobUrl || file.url;
78
+ }
79
+
74
80
  function getThumbUrl(file) {
75
- if (file.thumb) {
76
- return file.thumb.url;
77
- } else if (isVideo(file)) {
78
- // Base64 encode a PlayIcon for the placeholder image
79
- return `data:image/svg+xml;base64,${btoa(
80
- `<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>`
81
- )}`;
82
- } else {
83
- return file.url;
84
- }
81
+ if (file.thumb) {
82
+ return file.thumb.url;
83
+ } else if (isVideo(file)) {
84
+ // Base64 encode a PlayIcon for the placeholder image
85
+ return `data:image/svg+xml;base64,${btoa(
86
+ `<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>`
87
+ )}`;
88
+ } else {
89
+ return getPreviewUrl(file);
90
+ }
85
91
  }
86
92
  </script>
87
93
  <style module="cls" lang="scss">
88
94
  .slide-image {
89
- width: 100%;
90
- height: 100%;
91
- background: black;
92
- display: flex;
93
- justify-content: center;
94
- align-items: center;
95
+ width: 100%;
96
+ height: 100%;
97
+ background: black;
98
+ display: flex;
99
+ justify-content: center;
100
+ align-items: center;
95
101
 
96
- img {
97
- max-height: 100%;
98
- max-width: 100%;
99
- object-fit: contain;
100
- }
102
+ img {
103
+ max-height: 100%;
104
+ max-width: 100%;
105
+ object-fit: contain;
106
+ }
101
107
  }
102
108
 
103
109
  .carousel {
104
- :deep(.q-carousel__navigation--bottom) {
105
- position: relative;
106
- bottom: 8em;
107
- }
110
+ :deep(.q-carousel__navigation--bottom) {
111
+ position: relative;
112
+ bottom: 8em;
113
+ }
108
114
  }
109
115
  </style>
@@ -1,3 +1,4 @@
1
+ export { default as ConfirmActionDialog } from "./ConfirmActionDialog.vue";
1
2
  export { default as ConfirmDialog } from "./ConfirmDialog.vue";
2
3
  export { default as FullScreenCarouselDialog } from "./FullscreenCarouselDialog.vue";
3
4
  export { default as FullScreenDialog } from "./FullScreenDialog.vue";
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
  <QImg
29
29
  v-if="thumbUrl || isPreviewable"
30
- fit="scale-down"
30
+ :fit="imageFit"
31
31
  class="non-selectable max-h-full max-w-full h-full"
32
32
  :src="(thumbUrl || previewUrl) + '#t=0.1'"
33
33
  preload="auto"
@@ -54,11 +54,11 @@
54
54
  <slot name="action-button" />
55
55
  </div>
56
56
  <div
57
- v-if="image && image.progress !== undefined"
57
+ v-if="file && file.progress !== undefined"
58
58
  class="absolute-bottom w-full"
59
59
  >
60
60
  <QLinearProgress
61
- :value="image.progress"
61
+ :value="file.progress"
62
62
  size="15px"
63
63
  color="green-600"
64
64
  stripe
@@ -78,7 +78,7 @@
78
78
  <QBtn
79
79
  v-if="downloadable && computedImage?.url"
80
80
  size="sm"
81
- class="!p-1 opacity-70 hover:opacity-100"
81
+ class="dx-file-preview-download py-1 px-2 opacity-70 hover:opacity-100"
82
82
  :class="downloadButtonClass"
83
83
  @click.stop="download(computedImage.url)"
84
84
  >
@@ -88,7 +88,7 @@
88
88
  <QBtn
89
89
  v-if="removable"
90
90
  size="sm"
91
- class="bg-red-900 text-white !p-1 opacity-50 hover:opacity-100"
91
+ class="dx-file-preview-remove bg-red-900 text-white opacity-50 hover:opacity-100 py-1 px-2"
92
92
  @click.stop="onRemove"
93
93
  >
94
94
  <div
@@ -107,106 +107,109 @@
107
107
  <FullScreenCarouselDialog
108
108
  v-if="showPreview && !disabled"
109
109
  :files="relatedFiles || [computedImage]"
110
- :default-slide="computedImage.id"
110
+ :default-slide="computedImage?.id || ''"
111
111
  @close="showPreview = false"
112
112
  />
113
113
  </div>
114
114
  </template>
115
115
 
116
- <script setup>
116
+ <script setup lang="ts">
117
117
  import { DocumentTextIcon as TextFileIcon, DownloadIcon, PlayIcon } from "@heroicons/vue/outline";
118
- import { computed, ref } from "vue";
118
+ import { UploadedFile } from "src/types";
119
+ import { computed, ComputedRef, ref } from "vue";
119
120
  import { download } from "../../../helpers";
120
121
  import { ImageIcon, PdfIcon, TrashIcon as RemoveIcon } from "../../../svg";
121
122
  import { FullScreenCarouselDialog } from "../Dialogs";
122
123
 
124
+ export interface FilePreviewProps {
125
+ src?: string;
126
+ file?: UploadedFile;
127
+ relatedFiles?: UploadedFile[];
128
+ missingIcon?: any;
129
+ downloadButtonClass?: string;
130
+ imageFit?: "cover" | "contain" | "fill" | "none" | "scale-down";
131
+ downloadable?: boolean;
132
+ removable?: boolean;
133
+ disabled?: boolean;
134
+ square?: boolean;
135
+ }
136
+
123
137
  const emit = defineEmits(["remove"]);
124
- const props = defineProps({
125
- src: {
126
- type: String,
127
- default: ""
128
- },
129
- image: {
130
- type: Object,
131
- default: null
132
- },
133
- relatedFiles: {
134
- type: Array,
135
- default: null
136
- },
137
- missingIcon: {
138
- type: [Function, Object],
139
- default: ImageIcon
140
- },
141
- downloadButtonClass: {
142
- type: String,
143
- default: "bg-blue-600 text-white"
144
- },
145
- downloadable: Boolean,
146
- removable: Boolean,
147
- disabled: Boolean,
148
- square: Boolean
138
+
139
+ const props = withDefaults(defineProps<FilePreviewProps>(), {
140
+ src: "",
141
+ file: null,
142
+ relatedFiles: null,
143
+ missingIcon: ImageIcon,
144
+ downloadButtonClass: "bg-blue-600 text-white",
145
+ imageFit: "cover",
146
+ downloadable: false,
147
+ removable: false,
148
+ disabled: false,
149
+ square: false
149
150
  });
150
151
 
151
152
  const showPreview = ref(false);
152
- const computedImage = computed(() => {
153
- if (props.image) {
154
- return props.image;
155
- } else if (props.src) {
156
- return {
157
- id: props.src,
158
- url: props.src,
159
- type: "image/" + props.src.split(".").pop().toLowerCase()
160
- };
161
- }
162
- return null;
153
+ const computedImage: ComputedRef<UploadedFile | null> = computed(() => {
154
+ if (props.file) {
155
+ return props.file;
156
+ } else if (props.src) {
157
+ return {
158
+ id: props.src,
159
+ url: props.src,
160
+ type: "image/" + props.src.split(".").pop()?.toLowerCase(),
161
+ name: "",
162
+ size: 0
163
+ };
164
+ }
165
+ return null;
163
166
  });
164
167
  const mimeType = computed(
165
- () => computedImage.value.type || computedImage.value.mime
168
+ () => computedImage.value?.type || computedImage.value?.mime || ""
166
169
  );
167
- const isImage = computed(() => mimeType.value.match(/^image\//));
168
- const isVideo = computed(() => mimeType.value.match(/^video\//));
169
- const isPdf = computed(() => mimeType.value.match(/^application\/pdf/));
170
+ const isImage = computed(() => !!mimeType.value.match(/^image\//));
171
+ const isVideo = computed(() => !!mimeType.value.match(/^video\//));
172
+ const isPdf = computed(() => !!mimeType.value.match(/^application\/pdf/));
170
173
  const previewUrl = computed(
171
- () => computedImage.value.transcodes?.compress?.url || computedImage.value.blobUrl || computedImage.value.url
174
+ () => computedImage.value?.transcodes?.compress?.url || computedImage.value?.blobUrl || computedImage.value?.url
172
175
  );
173
176
  const thumbUrl = computed(() => {
174
- return computedImage.value.transcodes?.thumb?.url;
177
+ return computedImage.value?.transcodes?.thumb?.url;
175
178
  });
176
179
  const isPreviewable = computed(() => {
177
- return !!thumbUrl.value || isVideo.value || isImage.value;
180
+ return !!thumbUrl.value || isVideo.value || isImage.value;
178
181
  });
179
182
  const isConfirmingRemove = ref(false);
180
183
  function onRemove() {
181
- if (!isConfirmingRemove.value) {
182
- isConfirmingRemove.value = true;
183
- setTimeout(() => {
184
- isConfirmingRemove.value = false;
185
- }, 2000);
186
- } else {
187
- emit("remove");
188
- }
184
+ if (!isConfirmingRemove.value) {
185
+ isConfirmingRemove.value = true;
186
+ setTimeout(() => {
187
+ isConfirmingRemove.value = false;
188
+ }, 2000);
189
+ } else {
190
+ emit("remove");
191
+ }
189
192
  }
190
193
  </script>
191
194
 
192
195
  <style module="cls" lang="scss">
193
196
  .action-button {
194
- position: absolute;
195
- bottom: 1.5em;
196
- right: 1em;
197
- z-index: 1;
197
+ position: absolute;
198
+ bottom: 1.5em;
199
+ right: 1em;
200
+ z-index: 1;
198
201
  }
199
202
 
200
203
  .play-button {
201
- position: absolute;
202
- top: 0;
203
- left: 0;
204
- display: flex;
205
- justify-content: center;
206
- align-items: center;
207
- width: 100%;
208
- height: 100%;
209
- pointer-events: none;
210
- @apply text-blue-200;
204
+ position: absolute;
205
+ top: 0;
206
+ left: 0;
207
+ display: flex;
208
+ justify-content: center;
209
+ align-items: center;
210
+ width: 100%;
211
+ height: 100%;
212
+ pointer-events: none;
213
+ @apply text-blue-200;
211
214
  }
212
215
  </style>
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <QDialog
3
- v-model="isShowing"
3
+ :model-value="show"
4
4
  maximized
5
5
  :position="position"
6
6
  :seamless="seamless"
7
7
  :class="{'hide-backdrop': !overlay}"
8
+ @hide="$emit('update:show', false)"
8
9
  >
9
10
  <div>
10
11
  <div
@@ -21,45 +22,37 @@
21
22
  </QDialog>
22
23
  </template>
23
24
 
24
- <script setup>
25
- import { computed } from "vue";
25
+ <script setup lang="ts">
26
+ import { QDialogProps } from "quasar";
26
27
 
27
- const emit = defineEmits(["update:show"]);
28
-
29
- const props = defineProps({
30
- show: Boolean,
31
- seamless: Boolean,
32
- overlay: Boolean,
33
- position: {
34
- type: String,
35
- default: "bottom"
36
- },
37
- contentClass: {
38
- type: String,
39
- default: "py-8 px-12"
40
- },
41
- title: {
42
- type: String,
43
- default: "Edit"
44
- }
45
- });
28
+ export interface ContentDrawerProps {
29
+ show?: boolean,
30
+ overlay?: boolean,
31
+ position?: QDialogProps["position"],
32
+ seamless?: boolean,
33
+ contentClass?: string,
34
+ title?: string
35
+ }
46
36
 
47
- const isShowing = computed({
48
- get: () => props.show,
49
- set: (value) => emit("update:show", value)
37
+ defineEmits(["update:show"]);
38
+ withDefaults(defineProps<ContentDrawerProps>(), {
39
+ show: false,
40
+ position: "bottom",
41
+ contentClass: "py-8 px-12",
42
+ title: "Edit"
50
43
  });
51
44
  </script>
52
45
 
53
46
  <style lang="scss" module="cls">
54
47
  .dialog-title {
55
- @apply font-medium uppercase text-xs px-6 py-3 border-b rounded-t-md bg-slate-100 text-gray-500 border-gray-200;
56
- font-family: "Roboto", sans-serif;
57
- letter-spacing: 0.05em;
58
- box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.25);
48
+ @apply font-medium uppercase text-xs px-6 py-3 border-b rounded-t-md bg-slate-100 text-gray-500 border-gray-200;
49
+ font-family: "Roboto", sans-serif;
50
+ letter-spacing: 0.05em;
51
+ box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.25);
59
52
  }
60
53
 
61
54
  .dialog-content {
62
- @apply bg-white;
63
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
55
+ @apply bg-white;
56
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
64
57
  }
65
58
  </style>
@@ -16,8 +16,8 @@ import RenderVnode from "./RenderVnode";
16
16
 
17
17
  const isSaving = ref(false);
18
18
  async function onConfirm(input) {
19
- isSaving.value = true;
20
- await activeActionVnode.value.confirm(input);
21
- isSaving.value = false;
19
+ isSaving.value = true;
20
+ await activeActionVnode.value.confirm(input);
21
+ isSaving.value = false;
22
22
  }
23
23
  </script>
@@ -5,7 +5,7 @@ const RenderVnode = (props) => {
5
5
  if (isVNode(props.vnode)) {
6
6
  return props.vnode;
7
7
  }
8
-
8
+
9
9
  if (isRef(props.vnode)) {
10
10
  return props.vnode.value;
11
11
  }