quasar-ui-danx 0.4.94 → 0.4.95

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.94",
3
+ "version": "0.4.95",
4
4
  "author": "Dan <dan@flytedesk.com>",
5
5
  "description": "DanX Vue / Quasar component library",
6
6
  "license": "MIT",
@@ -37,8 +37,12 @@
37
37
  v-else
38
38
  class="flex items-center justify-center h-full"
39
39
  >
40
+ <GoogleDocsIcon
41
+ v-if="isExternalLink"
42
+ class="h-3/4"
43
+ />
40
44
  <PdfIcon
41
- v-if="isPdf"
45
+ v-else-if="isPdf"
42
46
  class="w-3/4"
43
47
  />
44
48
  <TextFileIcon
@@ -163,8 +167,8 @@ import { computed, ComputedRef, onMounted, ref, watch } from "vue";
163
167
  import { danxOptions } from "../../../config";
164
168
  import { download, uniqueBy } from "../../../helpers";
165
169
  import * as fileHelpers from "../../../helpers/filePreviewHelpers";
166
- import { getMimeType, getOptimizedUrl } from "../../../helpers/filePreviewHelpers";
167
- import { ImageIcon, PdfIcon, TrashIcon as RemoveIcon } from "../../../svg";
170
+ import { getMimeType, getOptimizedUrl, isExternalLinkFile } from "../../../helpers/filePreviewHelpers";
171
+ import { GoogleDocsIcon, ImageIcon, PdfIcon, TrashIcon as RemoveIcon } from "../../../svg";
168
172
  import { UploadedFile } from "../../../types";
169
173
  import { FullScreenCarouselDialog } from "../Dialogs";
170
174
 
@@ -245,6 +249,7 @@ const mimeType = computed(() => computedImage.value ? getMimeType(computedImage.
245
249
  const isImage = computed(() => computedImage.value ? fileHelpers.isImage(computedImage.value) : false);
246
250
  const isVideo = computed(() => computedImage.value ? fileHelpers.isVideo(computedImage.value) : false);
247
251
  const isPdf = computed(() => computedImage.value ? fileHelpers.isPdf(computedImage.value) : false);
252
+ const isExternalLink = computed(() => computedImage.value ? isExternalLinkFile(computedImage.value) : false);
248
253
  const previewUrl = computed(() => computedImage.value ? getOptimizedUrl(computedImage.value) : "");
249
254
  const thumbUrl = computed(() => computedImage.value?.thumb?.url || "");
250
255
  const isPreviewable = computed(() => {
@@ -281,6 +286,11 @@ function onRemove() {
281
286
  }
282
287
 
283
288
  function onShowPreview() {
289
+ // For external links (Google Docs, etc.), open directly in new tab
290
+ if (computedImage.value && isExternalLinkFile(computedImage.value)) {
291
+ window.open(computedImage.value.url, "_blank");
292
+ return;
293
+ }
284
294
  showPreview.value = true;
285
295
  }
286
296
 
@@ -105,3 +105,34 @@ export function getThumbUrl(file: UploadedFile): string {
105
105
  export function getOptimizedUrl(file: UploadedFile): string {
106
106
  return file.optimized?.url || file.blobUrl || file.url || "";
107
107
  }
108
+
109
+ /**
110
+ * Check if file is an external link that should open in a new tab
111
+ * (e.g., Google Docs, external URLs that can't be previewed inline)
112
+ */
113
+ export function isExternalLinkFile(file: UploadedFile): boolean {
114
+ const url = file.url || "";
115
+ const mime = getMimeType(file);
116
+
117
+ // Google Docs/Sheets/Slides URLs
118
+ if (url.includes("docs.google.com") || url.includes("drive.google.com")) {
119
+ return true;
120
+ }
121
+
122
+ // Google Doc MIME types
123
+ if (mime.startsWith("application/vnd.google-apps.")) {
124
+ return true;
125
+ }
126
+
127
+ return false;
128
+ }
129
+
130
+ /**
131
+ * Check if file can be previewed inline (image, video, text, pdf)
132
+ */
133
+ export function canPreviewInline(file: UploadedFile): boolean {
134
+ if (isExternalLinkFile(file)) {
135
+ return false;
136
+ }
137
+ return isImage(file) || isVideo(file) || isText(file) || isPdf(file) || !!file.thumb?.url;
138
+ }
@@ -25,7 +25,12 @@ export function storeObject<T extends TypedObject>(newObject: T, recentlyStoredO
25
25
 
26
26
  const id = newObject?.id || newObject?.name;
27
27
  const type = newObject?.__type;
28
- if (!id || !type) return shallowReactive(newObject);
28
+ if (!id || !type) {
29
+ // Still process children to store any nested TypedObjects
30
+ const reactiveObject = shallowReactive(newObject);
31
+ storeObjectChildren(newObject, recentlyStoredObjects, reactiveObject);
32
+ return reactiveObject;
33
+ }
29
34
 
30
35
  if (!newObject.__id) {
31
36
  newObject.__id = uid();
@@ -88,7 +93,7 @@ function storeObjectChildren<T extends TypedObject>(object: T, recentlyStoredObj
88
93
  applyToObject = applyToObject || object;
89
94
  for (const key of Object.keys(object)) {
90
95
  const value = object[key];
91
- if (Array.isArray(value) && value.length > 0) {
96
+ if (Array.isArray(value)) {
92
97
  for (const index in value) {
93
98
  if (value[index] && typeof value[index] === "object") {
94
99
  if (!applyToObject[key]) {
@@ -101,6 +106,9 @@ function storeObjectChildren<T extends TypedObject>(object: T, recentlyStoredObj
101
106
  } else if (value?.__type) {
102
107
  // @ts-expect-error __type is guaranteed to be set in this case
103
108
  applyToObject[key] = storeObject(value as TypedObject, recentlyStoredObjects);
109
+ } else if (value && typeof value === "object") {
110
+ // Handle plain objects/dictionaries - recurse to find nested TypedObjects at any depth
111
+ storeObjectChildren(value, recentlyStoredObjects, applyToObject[key]);
104
112
  }
105
113
  }
106
114
  }
@@ -0,0 +1,88 @@
1
+ <template>
2
+ <svg
3
+ viewBox="0 0 47 65"
4
+ xmlns="http://www.w3.org/2000/svg"
5
+ preserveAspectRatio="xMidYMid meet"
6
+ >
7
+ <defs>
8
+ <linearGradient
9
+ id="gdoc-gradient"
10
+ x1="50%"
11
+ y1="8.59%"
12
+ x2="50%"
13
+ y2="100%"
14
+ >
15
+ <stop
16
+ stop-color="#1A237E"
17
+ stop-opacity="0.2"
18
+ offset="0%"
19
+ />
20
+ <stop
21
+ stop-color="#1A237E"
22
+ stop-opacity="0.02"
23
+ offset="100%"
24
+ />
25
+ </linearGradient>
26
+ <radialGradient
27
+ id="gdoc-radial"
28
+ cx="3.17%"
29
+ cy="2.72%"
30
+ r="161.25%"
31
+ >
32
+ <stop
33
+ stop-color="#FFFFFF"
34
+ stop-opacity="0.1"
35
+ offset="0%"
36
+ />
37
+ <stop
38
+ stop-color="#FFFFFF"
39
+ stop-opacity="0"
40
+ offset="100%"
41
+ />
42
+ </radialGradient>
43
+ </defs>
44
+ <!-- Main document shape -->
45
+ <path
46
+ d="M29.375,0 L4.406,0 C1.983,0 0,1.994 0,4.432 L0,60.568 C0,63.006 1.983,65 4.406,65 L42.594,65 C45.017,65 47,63.006 47,60.568 L47,17.727 L36.719,10.341 L29.375,0 Z"
47
+ fill="#4285F4"
48
+ />
49
+ <!-- Corner fold shadow -->
50
+ <polygon
51
+ fill="url(#gdoc-gradient)"
52
+ points="30.664 16.431 47 32.858 47 17.727"
53
+ />
54
+ <!-- Text lines -->
55
+ <path
56
+ d="M11.75,47.273 L35.25,47.273 L35.25,44.318 L11.75,44.318 L11.75,47.273 Z M11.75,53.182 L29.375,53.182 L29.375,50.227 L11.75,50.227 L11.75,53.182 Z M11.75,32.5 L11.75,35.455 L35.25,35.455 L35.25,32.5 L11.75,32.5 Z M11.75,41.364 L35.25,41.364 L35.25,38.409 L11.75,38.409 L11.75,41.364 Z"
57
+ fill="#F1F1F1"
58
+ />
59
+ <!-- Corner fold -->
60
+ <path
61
+ d="M29.375,0 L29.375,13.295 C29.375,15.744 31.347,17.727 33.781,17.727 L47,17.727 L29.375,0 Z"
62
+ fill="#A1C2FA"
63
+ />
64
+ <!-- Top highlight -->
65
+ <path
66
+ d="M4.406,0 C1.983,0 0,1.994 0,4.432 L0,4.801 C0,2.364 1.983,0.369 4.406,0.369 L29.375,0.369 L29.375,0 L4.406,0 Z"
67
+ fill="#FFFFFF"
68
+ fill-opacity="0.2"
69
+ />
70
+ <!-- Bottom shadow -->
71
+ <path
72
+ d="M42.594,64.631 L4.406,64.631 C1.983,64.631 0,62.636 0,60.199 L0,60.568 C0,63.006 1.983,65 4.406,65 L42.594,65 C45.017,65 47,63.006 47,60.568 L47,60.199 C47,62.636 45.017,64.631 42.594,64.631 Z"
73
+ fill="#1A237E"
74
+ fill-opacity="0.2"
75
+ />
76
+ <!-- Fold edge shadow -->
77
+ <path
78
+ d="M33.781,17.727 C31.347,17.727 29.375,15.744 29.375,13.295 L29.375,13.665 C29.375,16.113 31.347,18.097 33.781,18.097 L47,18.097 L47,17.727 L33.781,17.727 Z"
79
+ fill="#1A237E"
80
+ fill-opacity="0.1"
81
+ />
82
+ <!-- Overlay gradient -->
83
+ <path
84
+ d="M29.375,0 L4.406,0 C1.983,0 0,1.994 0,4.432 L0,60.568 C0,63.006 1.983,65 4.406,65 L42.594,65 C45.017,65 47,63.006 47,60.568 L47,17.727 L29.375,0 Z"
85
+ fill="url(#gdoc-radial)"
86
+ />
87
+ </svg>
88
+ </template>
package/src/svg/index.ts CHANGED
@@ -2,6 +2,7 @@ export { default as CaretDownIcon } from "./CaretDownIcon.svg";
2
2
  export { default as DragHandleDotsIcon } from "./DragHandleDotsIcon.svg";
3
3
  export { default as DragHandleIcon } from "./DragHandleIcon.svg";
4
4
  export { default as FilterIcon } from "./FilterIcon.svg";
5
+ export { default as GoogleDocsIcon } from "./GoogleDocsIcon.vue";
5
6
  export { default as ImageIcon } from "./ImageIcon.svg";
6
7
  export { default as PdfIcon } from "./PdfIcon.svg";
7
8
  export { default as PercentIcon } from "./PercentIcon.svg";