nuxt-media-library 0.0.44 → 0.0.49

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 (111) hide show
  1. package/README.md +71 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +4 -1
  4. package/dist/runtime/components/MLAssetManager/Processing.vue +3 -1
  5. package/dist/runtime/components/MLMedia/Dropzone.d.vue.ts +60 -0
  6. package/dist/runtime/components/MLMedia/Dropzone.vue +137 -0
  7. package/dist/runtime/components/MLMedia/Dropzone.vue.d.ts +60 -0
  8. package/dist/runtime/components/MLMedia/Editor.d.vue.ts +23 -0
  9. package/dist/runtime/components/MLMedia/Editor.vue +34 -0
  10. package/dist/runtime/components/MLMedia/Editor.vue.d.ts +23 -0
  11. package/dist/runtime/components/MLMedia/EditorPanel.d.vue.ts +38 -0
  12. package/dist/runtime/components/MLMedia/EditorPanel.vue +220 -0
  13. package/dist/runtime/components/MLMedia/EditorPanel.vue.d.ts +38 -0
  14. package/dist/runtime/components/MLMedia/Field.d.vue.ts +65 -0
  15. package/dist/runtime/components/MLMedia/Field.vue +282 -0
  16. package/dist/runtime/components/MLMedia/Field.vue.d.ts +65 -0
  17. package/dist/runtime/components/MLMedia/FileFacts.d.vue.ts +19 -0
  18. package/dist/runtime/components/MLMedia/FileFacts.vue +38 -0
  19. package/dist/runtime/components/MLMedia/FileFacts.vue.d.ts +19 -0
  20. package/dist/runtime/components/MLMedia/FilePicker.d.vue.ts +23 -0
  21. package/dist/runtime/components/MLMedia/FilePicker.vue +33 -0
  22. package/dist/runtime/components/MLMedia/FilePicker.vue.d.ts +23 -0
  23. package/dist/runtime/components/MLMedia/FilePickerPanel.d.vue.ts +33 -0
  24. package/dist/runtime/components/MLMedia/FilePickerPanel.vue +300 -0
  25. package/dist/runtime/components/MLMedia/FilePickerPanel.vue.d.ts +33 -0
  26. package/dist/runtime/components/MLMedia/FilterPill.d.vue.ts +30 -0
  27. package/dist/runtime/components/MLMedia/FilterPill.vue +84 -0
  28. package/dist/runtime/components/MLMedia/FilterPill.vue.d.ts +30 -0
  29. package/dist/runtime/components/MLMedia/Gallery.d.vue.ts +78 -0
  30. package/dist/runtime/components/MLMedia/Gallery.vue +256 -0
  31. package/dist/runtime/components/MLMedia/Gallery.vue.d.ts +78 -0
  32. package/dist/runtime/components/MLMedia/GallerySection.d.vue.ts +102 -0
  33. package/dist/runtime/components/MLMedia/GallerySection.vue +422 -0
  34. package/dist/runtime/components/MLMedia/GallerySection.vue.d.ts +102 -0
  35. package/dist/runtime/components/MLMedia/KindBadge.d.vue.ts +17 -0
  36. package/dist/runtime/components/MLMedia/KindBadge.vue +22 -0
  37. package/dist/runtime/components/MLMedia/KindBadge.vue.d.ts +17 -0
  38. package/dist/runtime/components/MLMedia/MediaTile.d.vue.ts +63 -0
  39. package/dist/runtime/components/MLMedia/MediaTile.vue +117 -0
  40. package/dist/runtime/components/MLMedia/MediaTile.vue.d.ts +63 -0
  41. package/dist/runtime/components/MLMedia/PickerCard.d.vue.ts +42 -0
  42. package/dist/runtime/components/MLMedia/PickerCard.vue +79 -0
  43. package/dist/runtime/components/MLMedia/PickerCard.vue.d.ts +42 -0
  44. package/dist/runtime/components/MLMedia/PickerRow.d.vue.ts +31 -0
  45. package/dist/runtime/components/MLMedia/PickerRow.vue +65 -0
  46. package/dist/runtime/components/MLMedia/PickerRow.vue.d.ts +31 -0
  47. package/dist/runtime/components/MLMedia/PreviewEye.d.vue.ts +16 -0
  48. package/dist/runtime/components/MLMedia/PreviewEye.vue +21 -0
  49. package/dist/runtime/components/MLMedia/PreviewEye.vue.d.ts +16 -0
  50. package/dist/runtime/components/MLMedia/ProgressVeil.d.vue.ts +25 -0
  51. package/dist/runtime/components/MLMedia/ProgressVeil.vue +98 -0
  52. package/dist/runtime/components/MLMedia/ProgressVeil.vue.d.ts +25 -0
  53. package/dist/runtime/components/MLMedia/StatusBadge.d.vue.ts +17 -0
  54. package/dist/runtime/components/MLMedia/StatusBadge.vue +31 -0
  55. package/dist/runtime/components/MLMedia/StatusBadge.vue.d.ts +17 -0
  56. package/dist/runtime/components/MLMedia/Thumbnail.d.vue.ts +36 -0
  57. package/dist/runtime/components/MLMedia/Thumbnail.vue +84 -0
  58. package/dist/runtime/components/MLMedia/Thumbnail.vue.d.ts +36 -0
  59. package/dist/runtime/components/MLMedia/UsageList.d.vue.ts +26 -0
  60. package/dist/runtime/components/MLMedia/UsageList.vue +66 -0
  61. package/dist/runtime/components/MLMedia/UsageList.vue.d.ts +26 -0
  62. package/dist/runtime/components/MLProcessing/StepLayout.d.vue.ts +1 -1
  63. package/dist/runtime/components/MLProcessing/StepLayout.vue.d.ts +1 -1
  64. package/dist/runtime/components/MLUploader/Item.d.vue.ts +2 -2
  65. package/dist/runtime/components/MLUploader/Item.vue.d.ts +2 -2
  66. package/dist/runtime/composables/useMLAssetPreview.js +17 -1
  67. package/dist/runtime/composables/useMLFilePicker.d.ts +20 -0
  68. package/dist/runtime/composables/useMLFilePicker.js +17 -0
  69. package/dist/runtime/composables/useMLMediaAssets.d.ts +19 -0
  70. package/dist/runtime/composables/useMLMediaAssets.js +56 -0
  71. package/dist/runtime/composables/useMLMediaBrowse.d.ts +147 -0
  72. package/dist/runtime/composables/useMLMediaBrowse.js +72 -0
  73. package/dist/runtime/composables/useMLMediaEditor.d.ts +22 -0
  74. package/dist/runtime/composables/useMLMediaEditor.js +20 -0
  75. package/dist/runtime/composables/useMLMediaField.d.ts +29 -0
  76. package/dist/runtime/composables/useMLMediaField.js +77 -0
  77. package/dist/runtime/composables/useMLMediaGallery.d.ts +55 -0
  78. package/dist/runtime/composables/useMLMediaGallery.js +134 -0
  79. package/dist/runtime/composables/useMLMediaGrants.d.ts +23 -0
  80. package/dist/runtime/composables/useMLMediaGrants.js +22 -0
  81. package/dist/runtime/composables/useMLMediaUpload.d.ts +134 -0
  82. package/dist/runtime/composables/useMLMediaUpload.js +153 -0
  83. package/dist/runtime/composables/useMLServiceUpload.d.ts +36 -0
  84. package/dist/runtime/composables/useMLServiceUpload.js +32 -0
  85. package/dist/runtime/index.d.ts +11 -0
  86. package/dist/runtime/index.js +11 -0
  87. package/dist/runtime/server/create-ml-proxy.d.ts +16 -0
  88. package/dist/runtime/server/create-ml-proxy.js +138 -40
  89. package/dist/runtime/server/grants.d.ts +124 -0
  90. package/dist/runtime/server/grants.js +161 -0
  91. package/dist/runtime/server/index.d.ts +2 -0
  92. package/dist/runtime/server/index.js +7 -0
  93. package/dist/runtime/server/uploads-proxy.js +5 -2
  94. package/dist/runtime/types/asset.d.ts +3 -1
  95. package/dist/runtime/utils/assetDisplay.d.ts +8 -0
  96. package/dist/runtime/utils/assetDisplay.js +29 -0
  97. package/dist/runtime/utils/assetFormat.d.ts +30 -0
  98. package/dist/runtime/utils/assetFormat.js +69 -0
  99. package/dist/runtime/utils/assetThumbnail.d.ts +11 -0
  100. package/dist/runtime/utils/assetThumbnail.js +14 -0
  101. package/dist/runtime/utils/fileAccept.d.ts +26 -0
  102. package/dist/runtime/utils/fileAccept.js +104 -0
  103. package/dist/runtime/utils/galleryDrag.d.ts +2 -0
  104. package/dist/runtime/utils/galleryDrag.js +1 -0
  105. package/dist/runtime/utils/grants/listeners.d.ts +2 -0
  106. package/dist/runtime/utils/grants/listeners.js +8 -0
  107. package/dist/runtime/utils/grants/store.d.ts +26 -0
  108. package/dist/runtime/utils/grants/store.js +37 -0
  109. package/dist/runtime/utils/uploader/serviceUpload.d.ts +84 -0
  110. package/dist/runtime/utils/uploader/serviceUpload.js +109 -0
  111. package/package.json +5 -2
@@ -0,0 +1,117 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { assetDurationSeconds, assetName, formatDuration } from "../../utils/assetFormat";
4
+ const props = defineProps({
5
+ asset: { type: [Object, null], required: false, default: null },
6
+ src: { type: [String, null], required: false, default: void 0 },
7
+ kind: { type: [String, null], required: false, default: void 0 },
8
+ name: { type: String, required: false, default: void 0 },
9
+ duration: { type: [Number, null], required: false, default: void 0 },
10
+ missingAlt: { type: Boolean, required: false, default: false },
11
+ selectable: { type: Boolean, required: false, default: false },
12
+ selected: { type: Boolean, required: false, default: false },
13
+ selecting: { type: Boolean, required: false, default: false },
14
+ phase: { type: [String, null], required: false, default: null },
15
+ progress: { type: [Number, null], required: false, default: null },
16
+ phaseDetail: { type: String, required: false, default: void 0 },
17
+ disabled: { type: Boolean, required: false, default: false },
18
+ aspect: { type: String, required: false, default: "square" },
19
+ onOpen: { type: Function, required: false, default: void 0 }
20
+ });
21
+ const emit = defineEmits(["update:selected", "cancel", "retry"]);
22
+ defineSlots();
23
+ const resolvedKind = computed(() => (props.kind !== void 0 ? props.kind : props.asset?.kind) ?? "");
24
+ const resolvedName = computed(() => props.name ?? assetName(props.asset));
25
+ const isImage = computed(() => resolvedKind.value.toLowerCase() === "image");
26
+ const durationLabel = computed(() => formatDuration(props.duration !== void 0 ? props.duration : assetDurationSeconds(props.asset)));
27
+ function onKey(e) {
28
+ if (props.disabled) return;
29
+ if (e.key === "Enter" && props.onOpen) {
30
+ e.preventDefault();
31
+ props.onOpen();
32
+ } else if (e.key === " " && props.selectable) {
33
+ e.preventDefault();
34
+ emit("update:selected", !props.selected);
35
+ }
36
+ }
37
+ </script>
38
+
39
+ <template>
40
+ <div
41
+ class="group relative rounded-lg outline-offset-2 focus-visible:outline-2 focus-visible:outline-primary"
42
+ :class="[
43
+ selected ? 'ring-2 ring-primary' : '',
44
+ disabled ? 'pointer-events-none opacity-50' : selectable ? 'cursor-pointer' : ''
45
+ ]"
46
+ role="button"
47
+ :tabindex="disabled ? -1 : 0"
48
+ :aria-label="resolvedName"
49
+ :aria-pressed="selectable ? selected : void 0"
50
+ :aria-disabled="disabled || void 0"
51
+ @click="!disabled && selectable && emit('update:selected', !selected)"
52
+ @keydown="onKey"
53
+ >
54
+ <MLMediaThumbnail
55
+ :asset="asset"
56
+ :src="src"
57
+ :kind="resolvedKind"
58
+ :alt="resolvedName"
59
+ size="fill"
60
+ :aspect="aspect"
61
+ >
62
+ <MLMediaKindBadge
63
+ v-if="!isImage && resolvedKind"
64
+ :kind="resolvedKind"
65
+ size="sm"
66
+ variant="solid"
67
+ class="absolute bottom-1.5 left-1.5"
68
+ />
69
+ <span
70
+ v-if="durationLabel"
71
+ class="absolute bottom-1.5 right-1.5 rounded bg-black/70 px-1.5 font-mono text-[11px] text-white tabular-nums"
72
+ >{{ durationLabel }}</span>
73
+ <UBadge
74
+ v-if="missingAlt && isImage"
75
+ color="warning"
76
+ variant="solid"
77
+ size="sm"
78
+ label="No alt"
79
+ class="absolute right-1.5 top-1.5"
80
+ />
81
+
82
+ <slot />
83
+
84
+ <MLMediaProgressVeil
85
+ v-if="phase"
86
+ :phase="phase"
87
+ :progress="progress"
88
+ :detail="phaseDetail"
89
+ :on-cancel="phase !== 'failed' ? () => emit('cancel') : void 0"
90
+ :on-retry="phase === 'failed' ? () => emit('retry') : void 0"
91
+ />
92
+ </MLMediaThumbnail>
93
+
94
+ <MLMediaPreviewEye
95
+ v-if="onOpen && !disabled && phase !== 'uploading'"
96
+ :name="resolvedName"
97
+ :visible="selecting"
98
+ class="absolute bottom-1.5 right-1.5 z-20"
99
+ :class="durationLabel ? 'bottom-7' : ''"
100
+ @click="onOpen"
101
+ />
102
+
103
+ <div
104
+ v-if="selectable"
105
+ class="absolute left-1.5 top-1.5 z-20 flex rounded bg-default p-0.5 shadow-sm transition-opacity motion-reduce:transition-none"
106
+ :class="selected || selecting ? 'opacity-100' : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100'"
107
+ @click.stop
108
+ >
109
+ <UCheckbox
110
+ :model-value="selected"
111
+ :aria-label="`Select ${resolvedName}`"
112
+ tabindex="-1"
113
+ @update:model-value="(v) => emit('update:selected', v === true)"
114
+ />
115
+ </div>
116
+ </div>
117
+ </template>
@@ -0,0 +1,63 @@
1
+ import type { AssetDetail, DeliveryAsset } from '../../types/asset.js';
2
+ import type { ProgressVeilPhase } from './ProgressVeil.vue.js';
3
+ type __VLS_Props = {
4
+ asset?: AssetDetail | DeliveryAsset | null;
5
+ src?: string | null;
6
+ kind?: string | null;
7
+ name?: string;
8
+ /** Seconds. Read from the asset's renditions when omitted. */
9
+ duration?: number | null;
10
+ /** Shows the "No alt" warning. Only meaningful for images; the host knows where alt text lives. */
11
+ missingAlt?: boolean;
12
+ /** Shows the selection checkbox on hover and focus; always visible once anything is selected. */
13
+ selectable?: boolean;
14
+ selected?: boolean;
15
+ /** Put the checkbox on screen without hovering, e.g. while the gallery is in selection mode. */
16
+ selecting?: boolean;
17
+ /** Overlay for uploads and processing. Omit when the file is ready. */
18
+ phase?: ProgressVeilPhase | null;
19
+ progress?: number | null;
20
+ phaseDetail?: string;
21
+ disabled?: boolean;
22
+ /** Fixed shape for grid cells. */
23
+ aspect?: 'square' | 'landscape' | 'portrait' | 'video';
24
+ /** Passing a listener shows the eye button, which opens the editor. Enter does the same. */
25
+ onOpen?: () => void;
26
+ };
27
+ type __VLS_Slots = {
28
+ /** Extra overlays, e.g. a drag handle or a "Featured" label. */
29
+ default?: () => unknown;
30
+ };
31
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
32
+ cancel: () => any;
33
+ retry: () => any;
34
+ "update:selected": (value: boolean) => any;
35
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
36
+ onCancel?: (() => any) | undefined;
37
+ onRetry?: (() => any) | undefined;
38
+ "onUpdate:selected"?: ((value: boolean) => any) | undefined;
39
+ }>, {
40
+ asset: AssetDetail | DeliveryAsset | null;
41
+ src: string | null;
42
+ progress: number | null;
43
+ name: string;
44
+ kind: string | null;
45
+ phase: ProgressVeilPhase | null;
46
+ disabled: boolean;
47
+ selected: boolean;
48
+ missingAlt: boolean;
49
+ onOpen: () => void;
50
+ duration: number | null;
51
+ selectable: boolean;
52
+ selecting: boolean;
53
+ phaseDetail: string;
54
+ aspect: "square" | "landscape" | "portrait" | "video";
55
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
56
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
57
+ declare const _default: typeof __VLS_export;
58
+ export default _default;
59
+ type __VLS_WithSlots<T, S> = T & {
60
+ new (): {
61
+ $slots: S;
62
+ };
63
+ };
@@ -0,0 +1,42 @@
1
+ import type { AssetDetail, DeliveryAsset } from '../../types/asset.js';
2
+ type __VLS_Props = {
3
+ asset?: AssetDetail | DeliveryAsset | null;
4
+ src?: string | null;
5
+ kind?: string | null;
6
+ name?: string;
7
+ /** Second line. Defaults to the file extension. */
8
+ meta?: string;
9
+ selected?: boolean;
10
+ /** Dimmed and not selectable, e.g. a kind the calling field doesn't accept. */
11
+ disabled?: boolean;
12
+ disabledReason?: string;
13
+ /** Passing a listener shows the preview button on hover. */
14
+ onPreview?: () => void;
15
+ };
16
+ type __VLS_Slots = {
17
+ /** Overlays on the thumbnail, e.g. an upload veil. */
18
+ default?: () => unknown;
19
+ };
20
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
21
+ toggle: () => any;
22
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
23
+ onToggle?: (() => any) | undefined;
24
+ }>, {
25
+ asset: AssetDetail | DeliveryAsset | null;
26
+ src: string | null;
27
+ name: string;
28
+ kind: string | null;
29
+ disabled: boolean;
30
+ meta: string;
31
+ selected: boolean;
32
+ disabledReason: string;
33
+ onPreview: () => void;
34
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
+ declare const _default: typeof __VLS_export;
37
+ export default _default;
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -0,0 +1,79 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { assetName, fileExtension } from "../../utils/assetFormat";
4
+ const props = defineProps({
5
+ asset: { type: [Object, null], required: false, default: null },
6
+ src: { type: [String, null], required: false, default: void 0 },
7
+ kind: { type: [String, null], required: false, default: void 0 },
8
+ name: { type: String, required: false, default: void 0 },
9
+ meta: { type: String, required: false, default: void 0 },
10
+ selected: { type: Boolean, required: false, default: false },
11
+ disabled: { type: Boolean, required: false, default: false },
12
+ disabledReason: { type: String, required: false, default: void 0 },
13
+ onPreview: { type: Function, required: false, default: void 0 }
14
+ });
15
+ const emit = defineEmits(["toggle"]);
16
+ defineSlots();
17
+ const resolvedKind = computed(() => props.kind !== void 0 ? props.kind : props.asset?.kind);
18
+ const resolvedName = computed(() => props.name ?? assetName(props.asset));
19
+ const subtitle = computed(() => props.meta ?? fileExtension(resolvedName.value));
20
+ const isTall = computed(() => (resolvedKind.value ?? "").toLowerCase() === "document");
21
+ </script>
22
+
23
+ <template>
24
+ <div
25
+ class="group relative rounded-lg"
26
+ :class="disabled ? 'opacity-40' : selected ? 'bg-elevated' : 'hover:bg-elevated'"
27
+ :title="disabled ? disabledReason : void 0"
28
+ >
29
+ <button
30
+ type="button"
31
+ class="flex w-full flex-col items-center gap-2 rounded-lg px-2.5 pb-2.5 pt-3 text-center outline-offset-2 focus-visible:outline-2 focus-visible:outline-primary"
32
+ :class="disabled ? 'cursor-not-allowed' : 'cursor-pointer'"
33
+ :aria-pressed="selected"
34
+ :disabled="disabled"
35
+ @click="emit('toggle')"
36
+ >
37
+ <span class="grid aspect-square w-full max-w-28 place-items-center rounded-md bg-default p-1 ring ring-default">
38
+ <MLMediaThumbnail
39
+ :asset="asset"
40
+ :src="src"
41
+ :kind="resolvedKind"
42
+ size="fill"
43
+ :aspect="isTall ? 'portrait' : 'landscape'"
44
+ :fit="isTall ? 'contain' : 'cover'"
45
+ :class="isTall ? 'w-3/4!' : ''"
46
+ class="rounded-sm! ring-0!"
47
+ >
48
+ <slot />
49
+ </MLMediaThumbnail>
50
+ </span>
51
+ <span class="flex w-full min-w-0 flex-col text-xs">
52
+ <span class="truncate">{{ resolvedName }}</span>
53
+ <span
54
+ v-if="subtitle"
55
+ class="text-muted"
56
+ >{{ subtitle }}</span>
57
+ </span>
58
+ </button>
59
+
60
+ <span
61
+ class="pointer-events-none absolute left-2 top-2 grid size-4 place-items-center rounded border-[1.5px]"
62
+ :class="selected ? 'border-inverted bg-inverted text-inverted' : 'border-accented bg-default'"
63
+ aria-hidden="true"
64
+ >
65
+ <UIcon
66
+ v-if="selected"
67
+ name="i-lucide-check"
68
+ class="size-3"
69
+ />
70
+ </span>
71
+
72
+ <MLMediaPreviewEye
73
+ v-if="onPreview && !disabled"
74
+ :name="resolvedName"
75
+ class="absolute bottom-12 right-2 z-10"
76
+ @click="onPreview"
77
+ />
78
+ </div>
79
+ </template>
@@ -0,0 +1,42 @@
1
+ import type { AssetDetail, DeliveryAsset } from '../../types/asset.js';
2
+ type __VLS_Props = {
3
+ asset?: AssetDetail | DeliveryAsset | null;
4
+ src?: string | null;
5
+ kind?: string | null;
6
+ name?: string;
7
+ /** Second line. Defaults to the file extension. */
8
+ meta?: string;
9
+ selected?: boolean;
10
+ /** Dimmed and not selectable, e.g. a kind the calling field doesn't accept. */
11
+ disabled?: boolean;
12
+ disabledReason?: string;
13
+ /** Passing a listener shows the preview button on hover. */
14
+ onPreview?: () => void;
15
+ };
16
+ type __VLS_Slots = {
17
+ /** Overlays on the thumbnail, e.g. an upload veil. */
18
+ default?: () => unknown;
19
+ };
20
+ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
21
+ toggle: () => any;
22
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
23
+ onToggle?: (() => any) | undefined;
24
+ }>, {
25
+ asset: AssetDetail | DeliveryAsset | null;
26
+ src: string | null;
27
+ name: string;
28
+ kind: string | null;
29
+ disabled: boolean;
30
+ meta: string;
31
+ selected: boolean;
32
+ disabledReason: string;
33
+ onPreview: () => void;
34
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
36
+ declare const _default: typeof __VLS_export;
37
+ export default _default;
38
+ type __VLS_WithSlots<T, S> = T & {
39
+ new (): {
40
+ $slots: S;
41
+ };
42
+ };
@@ -0,0 +1,31 @@
1
+ import type { AssetDetail, DeliveryAsset } from '../../types/asset.js';
2
+ type __VLS_Props = {
3
+ asset?: AssetDetail | DeliveryAsset | null;
4
+ src?: string | null;
5
+ kind?: string | null;
6
+ name?: string;
7
+ /** Defaults to the asset's size. */
8
+ size?: string;
9
+ /** Defaults to the asset's created date. */
10
+ date?: string;
11
+ selected?: boolean;
12
+ disabled?: boolean;
13
+ disabledReason?: string;
14
+ };
15
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
+ toggle: () => any;
17
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
18
+ onToggle?: (() => any) | undefined;
19
+ }>, {
20
+ size: string;
21
+ asset: AssetDetail | DeliveryAsset | null;
22
+ src: string | null;
23
+ name: string;
24
+ kind: string | null;
25
+ disabled: boolean;
26
+ selected: boolean;
27
+ date: string;
28
+ disabledReason: string;
29
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -0,0 +1,65 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { assetName, assetSizeBytes, formatBytes, formatShortDate } from "../../utils/assetFormat";
4
+ const props = defineProps({
5
+ asset: { type: [Object, null], required: false, default: null },
6
+ src: { type: [String, null], required: false, default: void 0 },
7
+ kind: { type: [String, null], required: false, default: void 0 },
8
+ name: { type: String, required: false, default: void 0 },
9
+ size: { type: String, required: false, default: void 0 },
10
+ date: { type: String, required: false, default: void 0 },
11
+ selected: { type: Boolean, required: false, default: false },
12
+ disabled: { type: Boolean, required: false, default: false },
13
+ disabledReason: { type: String, required: false, default: void 0 }
14
+ });
15
+ const emit = defineEmits(["toggle"]);
16
+ const resolvedKind = computed(() => props.kind !== void 0 ? props.kind : props.asset?.kind);
17
+ const resolvedName = computed(() => props.name ?? assetName(props.asset));
18
+ const sizeLabel = computed(() => {
19
+ if (props.size !== void 0) return props.size;
20
+ const bytes = assetSizeBytes(props.asset);
21
+ return bytes ? formatBytes(bytes) : "";
22
+ });
23
+ const dateLabel = computed(() => {
24
+ if (props.date !== void 0) return props.date;
25
+ const a = props.asset;
26
+ return a && "created_at" in a ? formatShortDate(a.created_at || a.createdAt) : "";
27
+ });
28
+ </script>
29
+
30
+ <template>
31
+ <button
32
+ type="button"
33
+ class="grid w-full grid-cols-[1rem_2.5rem_minmax(0,1fr)_auto] items-center gap-3 px-3 py-1.5 text-left text-sm outline-offset-[-2px] focus-visible:outline-2 focus-visible:outline-primary sm:grid-cols-[1rem_2.5rem_minmax(0,1fr)_auto_5rem_4.5rem]"
34
+ :class="[
35
+ selected ? 'bg-elevated' : 'hover:bg-elevated',
36
+ disabled ? 'cursor-not-allowed opacity-40' : 'cursor-pointer'
37
+ ]"
38
+ :aria-pressed="selected"
39
+ :disabled="disabled"
40
+ :title="disabled ? disabledReason : void 0"
41
+ @click="emit('toggle')"
42
+ >
43
+ <span
44
+ class="grid size-4 place-items-center rounded border-[1.5px]"
45
+ :class="selected ? 'border-inverted bg-inverted text-inverted' : 'border-accented bg-default'"
46
+ aria-hidden="true"
47
+ >
48
+ <UIcon
49
+ v-if="selected"
50
+ name="i-lucide-check"
51
+ class="size-3"
52
+ />
53
+ </span>
54
+ <MLMediaThumbnail
55
+ :asset="asset"
56
+ :src="src"
57
+ :kind="resolvedKind"
58
+ size="sm"
59
+ />
60
+ <span class="truncate">{{ resolvedName }}</span>
61
+ <MLMediaKindBadge :kind="resolvedKind" />
62
+ <span class="hidden text-right text-muted tabular-nums sm:block">{{ sizeLabel }}</span>
63
+ <span class="hidden text-right text-muted tabular-nums sm:block">{{ dateLabel }}</span>
64
+ </button>
65
+ </template>
@@ -0,0 +1,31 @@
1
+ import type { AssetDetail, DeliveryAsset } from '../../types/asset.js';
2
+ type __VLS_Props = {
3
+ asset?: AssetDetail | DeliveryAsset | null;
4
+ src?: string | null;
5
+ kind?: string | null;
6
+ name?: string;
7
+ /** Defaults to the asset's size. */
8
+ size?: string;
9
+ /** Defaults to the asset's created date. */
10
+ date?: string;
11
+ selected?: boolean;
12
+ disabled?: boolean;
13
+ disabledReason?: string;
14
+ };
15
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
16
+ toggle: () => any;
17
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
18
+ onToggle?: (() => any) | undefined;
19
+ }>, {
20
+ size: string;
21
+ asset: AssetDetail | DeliveryAsset | null;
22
+ src: string | null;
23
+ name: string;
24
+ kind: string | null;
25
+ disabled: boolean;
26
+ selected: boolean;
27
+ date: string;
28
+ disabledReason: string;
29
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
30
+ declare const _default: typeof __VLS_export;
31
+ export default _default;
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ /** File name, for the accessible label. */
3
+ name?: string;
4
+ /** Keep it visible without hovering (touch screens, selection mode). */
5
+ visible?: boolean;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
+ click: () => any;
9
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ onClick?: (() => any) | undefined;
11
+ }>, {
12
+ name: string;
13
+ visible: boolean;
14
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,21 @@
1
+ <script setup>
2
+ defineProps({
3
+ name: { type: String, required: false, default: "" },
4
+ visible: { type: Boolean, required: false, default: false }
5
+ });
6
+ const emit = defineEmits(["click"]);
7
+ </script>
8
+
9
+ <template>
10
+ <UButton
11
+ icon="i-lucide-eye"
12
+ color="info"
13
+ variant="solid"
14
+ size="xs"
15
+ square
16
+ class="rounded-md shadow-sm transition-opacity motion-reduce:transition-none"
17
+ :class="visible ? 'opacity-100' : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100'"
18
+ :aria-label="name ? `Preview ${name}` : 'Preview'"
19
+ @click.stop="emit('click')"
20
+ />
21
+ </template>
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ /** File name, for the accessible label. */
3
+ name?: string;
4
+ /** Keep it visible without hovering (touch screens, selection mode). */
5
+ visible?: boolean;
6
+ };
7
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
8
+ click: () => any;
9
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
10
+ onClick?: (() => any) | undefined;
11
+ }>, {
12
+ name: string;
13
+ visible: boolean;
14
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,25 @@
1
+ export type ProgressVeilPhase = 'uploading' | 'processing' | 'failed';
2
+ type __VLS_Props = {
3
+ phase: ProgressVeilPhase;
4
+ /** 0–100. Null or omitted shows an indeterminate bar (e.g. a step with no progress events). */
5
+ progress?: number | null;
6
+ /** Replaces the phase label, e.g. "Transcoding". */
7
+ label?: string;
8
+ /** Second line, usually the file name. */
9
+ detail?: string;
10
+ /** Bar only, no text. For thumbnails smaller than ~80px. */
11
+ compact?: boolean;
12
+ /** Passing a listener shows the matching button. */
13
+ onCancel?: () => void;
14
+ onRetry?: () => void;
15
+ };
16
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
17
+ progress: number | null;
18
+ label: string;
19
+ compact: boolean;
20
+ onCancel: () => void;
21
+ onRetry: () => void;
22
+ detail: string;
23
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;
@@ -0,0 +1,98 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ const props = defineProps({
4
+ phase: { type: String, required: true },
5
+ progress: { type: [Number, null], required: false, default: null },
6
+ label: { type: String, required: false, default: void 0 },
7
+ detail: { type: String, required: false, default: void 0 },
8
+ compact: { type: Boolean, required: false, default: false },
9
+ onCancel: { type: Function, required: false, default: void 0 },
10
+ onRetry: { type: Function, required: false, default: void 0 }
11
+ });
12
+ const PHASES = {
13
+ uploading: { label: "Uploading", color: "primary", icon: "i-lucide-upload" },
14
+ processing: { label: "Processing", color: "warning", icon: "i-lucide-loader-circle" },
15
+ failed: { label: "Failed", color: "error", icon: "i-lucide-circle-alert" }
16
+ };
17
+ const meta = computed(() => PHASES[props.phase]);
18
+ const value = computed(() => props.progress == null ? null : Math.round(Math.min(100, Math.max(0, props.progress))));
19
+ const heading = computed(() => {
20
+ const text = props.label ?? meta.value.label;
21
+ return value.value != null && props.phase !== "failed" ? `${text} ${value.value}%` : text;
22
+ });
23
+ </script>
24
+
25
+ <template>
26
+ <div
27
+ class="absolute inset-0 z-10 grid place-items-center bg-default/70 backdrop-blur-[2px]"
28
+ :class="compact ? 'p-1' : 'p-2'"
29
+ role="status"
30
+ aria-live="polite"
31
+ :aria-label="detail ? `${heading}: ${detail}` : heading"
32
+ >
33
+ <div
34
+ v-if="compact"
35
+ class="w-full self-end"
36
+ >
37
+ <UProgress
38
+ v-if="phase !== 'failed'"
39
+ :model-value="value"
40
+ :color="meta.color"
41
+ size="2xs"
42
+ />
43
+ <UIcon
44
+ v-else
45
+ :name="meta.icon"
46
+ class="mx-auto block size-4 text-error"
47
+ />
48
+ </div>
49
+
50
+ <div
51
+ v-else
52
+ class="flex w-full max-w-40 flex-col items-center gap-1.5 text-center"
53
+ >
54
+ <UIcon
55
+ :name="meta.icon"
56
+ class="size-4"
57
+ :class="{
58
+ 'animate-spin motion-reduce:animate-none': phase === 'processing',
59
+ 'text-error': phase === 'failed'
60
+ }"
61
+ />
62
+ <span class="text-xs font-semibold tabular-nums">{{ heading }}</span>
63
+ <span
64
+ v-if="detail"
65
+ class="w-full truncate text-xs text-muted"
66
+ >{{ detail }}</span>
67
+ <UProgress
68
+ v-if="phase !== 'failed'"
69
+ :model-value="value"
70
+ :color="meta.color"
71
+ size="xs"
72
+ class="w-4/5"
73
+ />
74
+ <div
75
+ v-if="onCancel || onRetry"
76
+ class="flex gap-1"
77
+ >
78
+ <UButton
79
+ v-if="onRetry && phase === 'failed'"
80
+ size="xs"
81
+ variant="soft"
82
+ color="neutral"
83
+ icon="i-lucide-rotate-ccw"
84
+ label="Retry"
85
+ @click.stop="onRetry"
86
+ />
87
+ <UButton
88
+ v-if="onCancel && phase !== 'failed'"
89
+ size="xs"
90
+ variant="ghost"
91
+ color="neutral"
92
+ label="Cancel"
93
+ @click.stop="onCancel"
94
+ />
95
+ </div>
96
+ </div>
97
+ </div>
98
+ </template>