quasar-ui-danx 0.4.52 → 0.4.54

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar-ui-danx",
3
- "version": "0.4.52",
3
+ "version": "0.4.54",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -41,6 +41,14 @@
41
41
  :alt="file.filename"
42
42
  :src="getPreviewUrl(file)"
43
43
  >
44
+ <div
45
+ v-else-if="isText(file)"
46
+ class="w-[60vw] min-w-96 bg-slate-800 rounded-lg"
47
+ >
48
+ <div class="whitespace-pre-wrap p-4">
49
+ {{ fileTexts[file.id] }}
50
+ </div>
51
+ </div>
44
52
  <div v-else>
45
53
  <h3 class="text-center mb-4">
46
54
  No Preview Available
@@ -71,8 +79,9 @@
71
79
  </div>
72
80
  </QDialog>
73
81
  </template>
74
- <script setup>
75
- import { ref } from "vue";
82
+ <script setup lang="ts">
83
+ import { QCarousel } from "quasar";
84
+ import { onMounted, ref, shallowRef } from "vue";
76
85
  import { XIcon as CloseIcon } from "../../../svg";
77
86
 
78
87
  defineEmits(["close"]);
@@ -97,6 +106,10 @@ function isImage(file) {
97
106
  return file.mime?.startsWith("image");
98
107
  }
99
108
 
109
+ function isText(file) {
110
+ return file.mime?.startsWith("text");
111
+ }
112
+
100
113
  function getPreviewUrl(file) {
101
114
  // Use the optimized URL first if available. If not, use the URL directly if its an image, otherwise use the thumb URL
102
115
  return file.optimized?.url || (isImage(file) ? (file.blobUrl || file.url) : file.thumb?.url);
@@ -111,8 +124,26 @@ function getThumbUrl(file) {
111
124
  `<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>`
112
125
  )}`;
113
126
  } else {
114
- return getPreviewUrl(file);
127
+ return getPreviewUrl(file) || "https://placehold.co/40x50?text=T";
128
+ }
129
+ }
130
+
131
+ onMounted(() => {
132
+ for (let file of props.files) {
133
+ if (isText(file)) {
134
+ loadFileText(file);
135
+ }
136
+ }
137
+ });
138
+
139
+ const fileTexts = shallowRef<{ [key: string]: string }>({});
140
+
141
+ async function loadFileText(file) {
142
+ if (fileTexts.value[file.id]) {
143
+ return fileTexts.value[file.id];
115
144
  }
145
+
146
+ fileTexts.value[file.id] = await fetch(file.url).then((res) => res.text());
116
147
  }
117
148
  </script>
118
149
  <style module="cls" lang="scss">
@@ -69,7 +69,8 @@
69
69
  class="absolute-bottom w-full bg-slate-800"
70
70
  >
71
71
  <QLinearProgress
72
- :value="isUploading ? file.progress : (transcodingStatus.progress / 100)"
72
+ :key="'progress-' + isUploading ? 'uploading' : 'transcoding'"
73
+ :value="isUploading ? file.progress : ((transcodingStatus?.progress || 0) / 100)"
73
74
  size="36px"
74
75
  :color="isUploading ? 'green-800' : 'blue-800'"
75
76
  :animation-speed="transcodingStatus?.estimate_ms || 3000"
@@ -77,12 +78,17 @@
77
78
  >
78
79
  <div class="absolute-full flex items-center flex-nowrap text-[.7rem] text-slate-200 justify-start px-1">
79
80
  <QSpinnerPie
80
- class="mr-2 text-slate-50 ml-1"
81
- size="20"
81
+ class="mr-2 text-slate-50 ml-1 flex-shrink-0"
82
+ :size="btnSize === 'xs' ? 10 : 20"
82
83
  />
83
- <div>
84
- {{ isUploading ? "Uploading..." : transcodingStatus.message }}
85
- </div>
84
+ <template v-if="statusMessage">
85
+ <div class="whitespace-nowrap overflow-hidden ellipsis">
86
+ {{ statusMessage }}
87
+ </div>
88
+ <QTooltip class="text-sm">
89
+ {{ statusMessage }}
90
+ </QTooltip>
91
+ </template>
86
92
  </div>
87
93
  </QLinearProgress>
88
94
  </div>
@@ -202,6 +208,7 @@ const computedImage: ComputedRef<UploadedFile | null> = computed(() => {
202
208
  });
203
209
 
204
210
  const isUploading = computed(() => !props.file || props.file?.progress !== undefined);
211
+ const statusMessage = computed(() => isUploading.value ? "Uploading..." : transcodingStatus.value?.message);
205
212
  const previewableFiles: ComputedRef<(UploadedFile | null)[] | null> = computed(() => {
206
213
  return props.relatedFiles?.length > 0 ? uniqueBy([computedImage.value, ...props.relatedFiles], filesHaveSameUrl) : [computedImage.value];
207
214
  });
@@ -44,10 +44,10 @@ export function storeObject<T extends TypedObject>(newObject: T, recentlyStoredO
44
44
  // Retrieve the existing object if it already exists in the store
45
45
  const oldObject = store.get(objectKey);
46
46
 
47
- // If an old object exists, and it is newer than the new object, do not store the new object, just return the old
47
+ // If an old object exists, and it is newer than the new object, and all the child objects are not newer than the original do not store the new object,
48
+ // just return the old
48
49
  // NOTE: If the timestamp is the same, its possible the intention is to update the existing object, so DO NOT return old object in this case
49
- // @ts-expect-error __timestamp is guaranteed to be set in this case on both old and new
50
- if (oldObject && newObject.__timestamp < oldObject.__timestamp) {
50
+ if (!hasRecentUpdates(newObject, oldObject)) {
51
51
  recentlyStoredObjects[objectKey] = oldObject;
52
52
 
53
53
  // Recursively store all the children of the object as well
@@ -105,6 +105,55 @@ function storeObjectChildren<T extends TypedObject>(object: T, recentlyStoredObj
105
105
  }
106
106
  }
107
107
 
108
+ /**
109
+ * Recursively check the current object and all its child objects
110
+ * to see if any of the objects are newer than the currently stored objects
111
+ */
112
+ function hasRecentUpdates(newObject: TypedObject, oldObject: TypedObject | null) {
113
+ // If there are no timestamps to compare, assume there are updates
114
+ if (!newObject.__timestamp || !oldObject?.__timestamp) return true;
115
+
116
+ // If the new object has a newer timestamp than the old then there are updates
117
+ if (newObject.__timestamp > oldObject.__timestamp) return true;
118
+
119
+ for (const key of Object.keys(newObject)) {
120
+ const newObjectValue = newObject[key];
121
+ const oldObjectValue = oldObject[key];
122
+
123
+ // If the old object does not have this key, this is new information, therefore there are updates
124
+ if (!oldObjectValue?.__timestamp) {
125
+ return true;
126
+ }
127
+
128
+ if (Array.isArray(newObjectValue) && newObjectValue.length > 0) {
129
+ for (const newObjectItem of newObjectValue as TypedObject[]) {
130
+ // Only compare the object if it is a TypedObject
131
+ if (newObjectItem?.__type) {
132
+ const oldObjectItem = (oldObjectValue as TypedObject[]).find((v: TypedObject) => v.id === newObjectItem.id && v.__type === newObjectItem.__type);
133
+
134
+ // If the oldObject does not have this entry, then there is new information, therefore there are updates
135
+ if (!oldObjectItem?.__timestamp) {
136
+ return true;
137
+ }
138
+
139
+ // Compare the child objects to see if there are updates
140
+ if (hasRecentUpdates(newObjectItem, oldObjectItem)) {
141
+ return true;
142
+ }
143
+ }
144
+ }
145
+ } else if (newObjectValue?.__type) {
146
+ // Only compare the object if it is a TypedObject
147
+ if (hasRecentUpdates(newObjectValue, oldObjectValue)) {
148
+ return true;
149
+ }
150
+ }
151
+ }
152
+
153
+ // If no updates were found, return false
154
+ return false;
155
+ }
156
+
108
157
  /**
109
158
  * Remove an object from all lists in the store
110
159
  */