quasar-ui-danx 0.4.92 → 0.4.93

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.
@@ -0,0 +1,43 @@
1
+ import { nextTick, Ref, watch } from "vue";
2
+
3
+ export interface UseThumbnailScrollOptions {
4
+ /**
5
+ * Container element that holds the thumbnails
6
+ */
7
+ containerRef: Ref<HTMLElement | null>;
8
+
9
+ /**
10
+ * Current active index
11
+ */
12
+ currentIndex: Ref<number>;
13
+
14
+ /**
15
+ * Optional CSS selector for thumbnail elements (defaults to '.thumbnail')
16
+ */
17
+ thumbnailSelector?: string;
18
+ }
19
+
20
+ /**
21
+ * Composable for auto-scrolling thumbnails into view
22
+ * Watches the current index and scrolls the active thumbnail into the visible area
23
+ */
24
+ export function useThumbnailScroll(options: UseThumbnailScrollOptions) {
25
+ const { containerRef, currentIndex, thumbnailSelector = ".thumbnail" } = options;
26
+
27
+ watch(currentIndex, (newIndex) => {
28
+ nextTick(() => {
29
+ const thumbnails = containerRef.value?.querySelectorAll(thumbnailSelector);
30
+ const activeThumbnail = thumbnails?.[newIndex] as HTMLElement;
31
+
32
+ if (activeThumbnail && containerRef.value) {
33
+ activeThumbnail.scrollIntoView({
34
+ behavior: "smooth",
35
+ block: "nearest",
36
+ inline: "center"
37
+ });
38
+ }
39
+ });
40
+ });
41
+
42
+ return {};
43
+ }
@@ -0,0 +1,93 @@
1
+ import { computed, Ref, shallowRef, watch } from "vue";
2
+ import { UploadedFile, VirtualCarouselSlide } from "../types";
3
+
4
+ const BUFFER_SIZE = 2; // Render current slide ± 2 slides
5
+
6
+ /**
7
+ * Composable for managing virtual carousel rendering
8
+ * Only renders slides within buffer window for performance with large file sets
9
+ */
10
+ export function useVirtualCarousel(
11
+ files: Ref<UploadedFile[]>,
12
+ currentIndex: Ref<number>
13
+ ) {
14
+ // Shallow ref to avoid deep reactivity for performance
15
+ const visibleSlides = shallowRef<VirtualCarouselSlide[]>([]);
16
+
17
+ /**
18
+ * Calculate which slides should be visible based on current index
19
+ */
20
+ const visibleIndices = computed(() => {
21
+ const start = Math.max(0, currentIndex.value - BUFFER_SIZE);
22
+ const end = Math.min(files.value.length - 1, currentIndex.value + BUFFER_SIZE);
23
+ const indices: number[] = [];
24
+
25
+ for (let i = start; i <= end; i++) {
26
+ indices.push(i);
27
+ }
28
+
29
+ return indices;
30
+ });
31
+
32
+ /**
33
+ * Update visible slides based on current index
34
+ */
35
+ function updateVisibleSlides() {
36
+ const indices = visibleIndices.value;
37
+ const newSlides: VirtualCarouselSlide[] = [];
38
+
39
+ for (const index of indices) {
40
+ if (index >= 0 && index < files.value.length) {
41
+ newSlides.push({
42
+ file: files.value[index],
43
+ index,
44
+ isActive: index === currentIndex.value,
45
+ isVisible: true
46
+ });
47
+ }
48
+ }
49
+
50
+ visibleSlides.value = newSlides;
51
+ }
52
+
53
+ /**
54
+ * Check if a slide at given index is visible
55
+ */
56
+ function isSlideVisible(index: number): boolean {
57
+ return visibleIndices.value.includes(index);
58
+ }
59
+
60
+ /**
61
+ * Get slide by index (returns null if not visible)
62
+ */
63
+ function getSlide(index: number): VirtualCarouselSlide | null {
64
+ return visibleSlides.value.find(s => s.index === index) || null;
65
+ }
66
+
67
+ /**
68
+ * Get slides that should be preloaded (visible + buffer)
69
+ */
70
+ const preloadIndices = computed(() => {
71
+ const start = Math.max(0, currentIndex.value - BUFFER_SIZE - 1);
72
+ const end = Math.min(files.value.length - 1, currentIndex.value + BUFFER_SIZE + 1);
73
+ const indices: number[] = [];
74
+
75
+ for (let i = start; i <= end; i++) {
76
+ indices.push(i);
77
+ }
78
+
79
+ return indices;
80
+ });
81
+
82
+ // Watch for changes to update visible slides
83
+ watch([currentIndex, files], updateVisibleSlides, { immediate: true });
84
+
85
+ return {
86
+ visibleSlides,
87
+ visibleIndices,
88
+ preloadIndices,
89
+ isSlideVisible,
90
+ getSlide,
91
+ updateVisibleSlides
92
+ };
93
+ }
@@ -0,0 +1,107 @@
1
+ import { UploadedFile } from "../types";
2
+
3
+ /**
4
+ * Placeholder constants for file preview
5
+ */
6
+ export const FILE_PLACEHOLDERS = {
7
+ IMAGE: "https://placehold.co/64x64?text=?",
8
+ VIDEO_SVG: `data:image/svg+xml;base64,${btoa(
9
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M8 5v14l11-7z"/></svg>'
10
+ )}`
11
+ };
12
+
13
+ /**
14
+ * MIME type regex patterns for file type detection
15
+ */
16
+ export const MIME_TYPES = {
17
+ IMAGE: /^image\//,
18
+ VIDEO: /^video\//,
19
+ TEXT: /^text\//,
20
+ PDF: /^application\/pdf/
21
+ };
22
+
23
+ /**
24
+ * Check if file is an image
25
+ */
26
+ export function isImage(file: UploadedFile): boolean {
27
+ const mimeType = getMimeType(file);
28
+ return MIME_TYPES.IMAGE.test(mimeType);
29
+ }
30
+
31
+ /**
32
+ * Check if file is a video
33
+ */
34
+ export function isVideo(file: UploadedFile): boolean {
35
+ const mimeType = getMimeType(file);
36
+ return MIME_TYPES.VIDEO.test(mimeType);
37
+ }
38
+
39
+ /**
40
+ * Check if file is a text file
41
+ */
42
+ export function isText(file: UploadedFile): boolean {
43
+ const mimeType = getMimeType(file);
44
+ return MIME_TYPES.TEXT.test(mimeType);
45
+ }
46
+
47
+ /**
48
+ * Check if file is a PDF
49
+ */
50
+ export function isPdf(file: UploadedFile): boolean {
51
+ const mimeType = getMimeType(file);
52
+ return MIME_TYPES.PDF.test(mimeType);
53
+ }
54
+
55
+ /**
56
+ * Get the MIME type from a file
57
+ */
58
+ export function getMimeType(file: UploadedFile): string {
59
+ return file.mime || file.type || "";
60
+ }
61
+
62
+ /**
63
+ * Get the file extension from a filename
64
+ */
65
+ export function getFileExtension(filename: string): string {
66
+ return filename.split(".").pop()?.toLowerCase() || "";
67
+ }
68
+
69
+ /**
70
+ * Get the preview URL for a file
71
+ * Priority: optimized > blobUrl > url > thumb > empty string
72
+ */
73
+ export function getPreviewUrl(file: UploadedFile): string {
74
+ if (file.optimized?.url) {
75
+ return file.optimized.url;
76
+ }
77
+
78
+ if (isImage(file)) {
79
+ return file.blobUrl || file.url || "";
80
+ }
81
+
82
+ return file.thumb?.url || "";
83
+ }
84
+
85
+ /**
86
+ * Get the thumbnail URL for a file
87
+ * For videos without thumbs, returns a play icon SVG
88
+ */
89
+ export function getThumbUrl(file: UploadedFile): string {
90
+ if (file.thumb?.url) {
91
+ return file.thumb.url;
92
+ }
93
+
94
+ if (isVideo(file)) {
95
+ return FILE_PLACEHOLDERS.VIDEO_SVG;
96
+ }
97
+
98
+ return getPreviewUrl(file) || FILE_PLACEHOLDERS.IMAGE;
99
+ }
100
+
101
+ /**
102
+ * Get the optimized URL for a file (used for preview)
103
+ * Priority: optimized > blobUrl > url
104
+ */
105
+ export function getOptimizedUrl(file: UploadedFile): string {
106
+ return file.optimized?.url || file.blobUrl || file.url || "";
107
+ }
@@ -8,6 +8,7 @@ export * from "./download";
8
8
  export * from "./downloadPdf";
9
9
  export * from "./files";
10
10
  export * from "./FileUpload";
11
+ export * from "./filePreviewHelpers";
11
12
  export * from "./FlashMessages";
12
13
  export * from "./formats";
13
14
  export * from "./hotkeys";
@@ -34,6 +34,23 @@ export interface UploadedFile extends TypedObject {
34
34
  meta?: AnyObject;
35
35
  }
36
36
 
37
+ export interface StoredFile extends TypedObject {
38
+ filename: string;
39
+ url: string;
40
+ mime: string;
41
+ size?: number;
42
+ location?: {
43
+ x: number;
44
+ y: number;
45
+ };
46
+ meta?: AnyObject;
47
+ page_number?: number;
48
+ is_transcoding?: boolean;
49
+ thumb?: StoredFile;
50
+ optimized?: StoredFile;
51
+ transcodes?: StoredFile[];
52
+ }
53
+
37
54
  export interface FileUploadCompleteCallbackParams {
38
55
  file?: UploadedFile | null;
39
56
  uploadedFile?: UploadedFile | null;
@@ -60,3 +77,24 @@ export type FileUploadProgressCallback = (params: FileUploadProgressCallbackPara
60
77
  export type FileUploadErrorCallback = (params: FileUploadErrorCallbackParams) => void
61
78
  export type OnFilesChangeCallback = (files: UploadedFile[]) => void;
62
79
  export type VoidCallback = () => void;
80
+
81
+ // File Navigation Types
82
+ export interface FileNavigationState {
83
+ currentFile: UploadedFile | null;
84
+ relatedFiles: UploadedFile[];
85
+ parentStack: FileNavigationParent[];
86
+ currentIndex: number;
87
+ }
88
+
89
+ export interface FileNavigationParent {
90
+ file: UploadedFile;
91
+ relatedFiles: UploadedFile[];
92
+ index: number;
93
+ }
94
+
95
+ export interface VirtualCarouselSlide {
96
+ file: UploadedFile;
97
+ index: number;
98
+ isActive: boolean;
99
+ isVisible: boolean;
100
+ }
@@ -1,5 +1,5 @@
1
1
  export interface LabelPillWidgetProps {
2
2
  label?: string | number;
3
3
  size?: "xs" | "sm" | "md" | "lg";
4
- color?: "sky" | "green" | "red" | "amber" | "yellow" | "blue" | "slate" | "slate-mid" | "gray" | "none";
4
+ color?: "sky" | "green" | "red" | "amber" | "yellow" | "blue" | "purple" | "slate" | "slate-mid" | "gray" | "emerald" | "orange" | "lime" | "teal" | "cyan" | "rose" | "indigo" | "violet" | "fuchsia" | "none";
5
5
  }
package/src/vue-plugin.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from "./config";
2
2
  export * from "./helpers";
3
3
  export * from "./components";
4
+ export * from "./composables";
4
5
  export * from "./svg";
5
6
 
6
7
  // eslint-disable-next-line import/extensions