@bagelink/vue 1.2.126 → 1.2.132
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/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/Carousel2.vue.d.ts +89 -0
- package/dist/components/Carousel2.vue.d.ts.map +1 -0
- package/dist/components/DragOver.vue.d.ts +1 -0
- package/dist/components/DragOver.vue.d.ts.map +1 -1
- package/dist/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/components/ImportData.vue.d.ts.map +1 -1
- package/dist/components/Loading.vue.d.ts +1 -0
- package/dist/components/Loading.vue.d.ts.map +1 -1
- package/dist/components/Modal.vue.d.ts +10 -5
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/Pill.vue.d.ts +2 -0
- package/dist/components/Pill.vue.d.ts.map +1 -1
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts +2 -2
- package/dist/components/calendar/views/CalendarPopover.vue.d.ts.map +1 -1
- package/dist/components/dataTable/DataTable.vue.d.ts.map +1 -1
- package/dist/components/dataTable/useTableData.d.ts +10 -10
- package/dist/components/dataTable/useTableData.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts +5 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/upload.types.d.ts +2 -0
- package/dist/components/form/inputs/Upload/upload.types.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/useFileUpload.d.ts +8 -1
- package/dist/components/form/inputs/Upload/useFileUpload.d.ts.map +1 -1
- package/dist/components/form/inputs/index.d.ts +0 -1
- package/dist/components/form/inputs/index.d.ts.map +1 -1
- package/dist/index.cjs +599 -1008
- package/dist/index.mjs +599 -1008
- package/dist/style.css +1747 -1932
- package/dist/types/BagelForm.d.ts.map +1 -1
- package/dist/types/TableSchema.d.ts +1 -1
- package/dist/types/TableSchema.d.ts.map +1 -1
- package/dist/utils/BagelFormUtils.d.ts +2 -2
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/DragOver.vue +21 -2
- package/src/components/ImportData.vue +34 -33
- package/src/components/Loading.vue +58 -50
- package/src/components/Modal.vue +10 -4
- package/src/components/Pill.vue +28 -5
- package/src/components/dataTable/DataTable.vue +5 -11
- package/src/components/dataTable/useTableData.ts +11 -10
- package/src/components/form/inputs/SelectInput.vue +1 -1
- package/src/components/form/inputs/Upload/UploadInput.vue +35 -47
- package/src/components/form/inputs/Upload/upload.css +12 -9
- package/src/components/form/inputs/Upload/upload.types.ts +2 -0
- package/src/components/form/inputs/Upload/useFileUpload.ts +35 -9
- package/src/components/form/inputs/index.ts +0 -1
- package/src/styles/layout.css +1466 -1460
- package/src/styles/theme.css +2 -1
- package/src/types/BagelForm.ts +2 -0
- package/src/types/TableSchema.ts +1 -1
- package/src/utils/BagelFormUtils.ts +2 -2
- package/dist/types/timeago.d.ts +0 -23
- package/dist/types/timeago.d.ts.map +0 -1
- package/src/components/form/inputs/FileUpload.vue +0 -724
package/src/components/Pill.vue
CHANGED
|
@@ -25,6 +25,8 @@ const props = defineProps<{
|
|
|
25
25
|
round?: boolean
|
|
26
26
|
btn?: BtnProp
|
|
27
27
|
btnEnd?: BtnProp
|
|
28
|
+
large?: boolean
|
|
29
|
+
small?: boolean
|
|
28
30
|
}>()
|
|
29
31
|
|
|
30
32
|
const slots: SetupContext['slots'] = useSlots()
|
|
@@ -77,11 +79,14 @@ const computedBackgroundColor = $computed(
|
|
|
77
79
|
|
|
78
80
|
<template>
|
|
79
81
|
<div
|
|
82
|
+
style="height: var(--pill-height);"
|
|
80
83
|
:disabled="disabled" :class="{
|
|
81
84
|
'bgl_pill': !icon || slots.default || value,
|
|
82
85
|
round,
|
|
83
86
|
'bgl_flatPill': flat,
|
|
84
87
|
'bgl_pill-border': border || outline,
|
|
88
|
+
'pillLarge': large,
|
|
89
|
+
'pillSmall': small,
|
|
85
90
|
}"
|
|
86
91
|
>
|
|
87
92
|
<div class="bgl_pill-flex">
|
|
@@ -91,12 +96,18 @@ const computedBackgroundColor = $computed(
|
|
|
91
96
|
<Btn class="bgl_pill-btn" round thin v-bind="btn" />
|
|
92
97
|
</div>
|
|
93
98
|
</div>
|
|
94
|
-
<Icon v-if="icon" :icon="icon" />
|
|
99
|
+
<Icon v-if="icon" :icon="icon" style="font-size: var(--pill-font-size)" />
|
|
95
100
|
<slot />
|
|
96
101
|
<template v-if="!slots.default">
|
|
97
|
-
|
|
102
|
+
<p
|
|
103
|
+
class="pillText"
|
|
104
|
+
>
|
|
105
|
+
{{ value || modelValue }}
|
|
106
|
+
{{ slots.default ? slots.default : value || modelValue }}
|
|
107
|
+
{{ value || modelValue }}
|
|
108
|
+
</p>
|
|
98
109
|
</template>
|
|
99
|
-
<Icon v-if="iconEnd" :icon="iconEnd" />
|
|
110
|
+
<Icon v-if="iconEnd" :icon="iconEnd" style="font-size: var(--pill-font-size)" />
|
|
100
111
|
<div v-if="loading" class="loading" />
|
|
101
112
|
<div v-else>
|
|
102
113
|
<div v-if="btnEnd" class="flex h-100">
|
|
@@ -108,6 +119,17 @@ const computedBackgroundColor = $computed(
|
|
|
108
119
|
</template>
|
|
109
120
|
|
|
110
121
|
<style scoped>
|
|
122
|
+
.pillLarge{
|
|
123
|
+
--pill-font-size: var(--bgl-font-size);
|
|
124
|
+
--pill-height:auto;
|
|
125
|
+
}
|
|
126
|
+
.pillSmall{
|
|
127
|
+
--pill-font-size: 9px;
|
|
128
|
+
--pill-height:15px;
|
|
129
|
+
}
|
|
130
|
+
.pillText{
|
|
131
|
+
font-size: var(--pill-font-size);
|
|
132
|
+
}
|
|
111
133
|
.bgl_pill-btn{
|
|
112
134
|
color: var(--pill-btn-color);
|
|
113
135
|
background: var(--pill-btn-bg);
|
|
@@ -137,14 +159,15 @@ const computedBackgroundColor = $computed(
|
|
|
137
159
|
}
|
|
138
160
|
|
|
139
161
|
.bgl_pill {
|
|
140
|
-
padding-inline:
|
|
162
|
+
padding-inline: calc(var(--pill-font-size) / 6);
|
|
163
|
+
padding-block: calc(var(--pill-font-size) / 24);
|
|
141
164
|
transition: var(--bgl-transition);
|
|
142
165
|
background-color: v-bind(computedBackgroundColor);
|
|
143
166
|
color: v-bind(cumputedTextColor);
|
|
144
167
|
display: inline-block;
|
|
145
168
|
margin-inline-end: 0.25rem;
|
|
146
169
|
border-radius: var(--pill-border-radius);
|
|
147
|
-
height: var(--pill-height);
|
|
170
|
+
min-height: var(--pill-height);
|
|
148
171
|
vertical-align: middle;
|
|
149
172
|
margin-bottom: 0.25rem;
|
|
150
173
|
}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
keyToLabel,
|
|
8
8
|
getNestedValue
|
|
9
9
|
} from '@bagelink/vue'
|
|
10
|
-
import { useSlots, watch, computed } from 'vue'
|
|
10
|
+
import { useSlots, watch, computed, toValue } from 'vue'
|
|
11
11
|
import { useSchemaField } from '../../composables/useSchemaField'
|
|
12
12
|
import { useTableData } from './useTableData'
|
|
13
13
|
import { useTableSelection } from './useTableSelection'
|
|
@@ -30,12 +30,6 @@ const loading = defineModel('loading', { default: false })
|
|
|
30
30
|
const itemHeight = defineModel('itemHeight', { default: 50 })
|
|
31
31
|
const selectedItems = defineModel<string[]>('selectedItems', { default: [] as string[] })
|
|
32
32
|
|
|
33
|
-
// Create computed properties to wrap the props
|
|
34
|
-
const data = computed(() => props.data)
|
|
35
|
-
const schema = computed(() => props.schema as any)
|
|
36
|
-
const columns = computed(() => props.columns as any)
|
|
37
|
-
const useServerSort = computed(() => props.useServerSort as any)
|
|
38
|
-
|
|
39
33
|
const {
|
|
40
34
|
computedSchema,
|
|
41
35
|
computedData,
|
|
@@ -44,10 +38,10 @@ const {
|
|
|
44
38
|
toggleSort,
|
|
45
39
|
cleanTransformedData
|
|
46
40
|
} = useTableData<T>({
|
|
47
|
-
data,
|
|
48
|
-
schema,
|
|
49
|
-
columns,
|
|
50
|
-
useServerSort,
|
|
41
|
+
data: computed(() => props.data),
|
|
42
|
+
schema: computed(() => toValue(props.schema)),
|
|
43
|
+
columns: computed(() => toValue(props.columns)),
|
|
44
|
+
useServerSort: computed(() => toValue(props.useServerSort)),
|
|
51
45
|
onSort: (field, direction) => {
|
|
52
46
|
emit('orderBy', `${field.trim()} ${direction.trim()}` as EmitOrderT)
|
|
53
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BglFormSchemaT } from '@bagelink/vue'
|
|
2
|
-
import type {
|
|
2
|
+
import type { MaybeRefOrGetter } from 'vue'
|
|
3
3
|
import type { SortDirectionsT } from '../../types/TableSchema'
|
|
4
4
|
import { useBglSchema, isDate, keyToLabel } from '@bagelink/vue'
|
|
5
5
|
import { computed, ref, watch, toValue } from 'vue'
|
|
@@ -14,10 +14,10 @@ const SRC_VALUE_COMPONENTS = new Set(['img', 'iframe'])
|
|
|
14
14
|
|
|
15
15
|
// Extend the base options interface to include computed refs
|
|
16
16
|
export interface UseTableDataOptions<T> {
|
|
17
|
-
data:
|
|
18
|
-
schema?: MaybeRefOrGetter<BglFormSchemaT<T
|
|
19
|
-
columns?: MaybeRefOrGetter<string[]>
|
|
20
|
-
useServerSort?: MaybeRefOrGetter<boolean>
|
|
17
|
+
data: MaybeRefOrGetter<T[]>
|
|
18
|
+
schema?: MaybeRefOrGetter<BglFormSchemaT<T> | undefined>
|
|
19
|
+
columns?: MaybeRefOrGetter<string[] | undefined>
|
|
20
|
+
useServerSort?: MaybeRefOrGetter<boolean | undefined>
|
|
21
21
|
onSort?: (field: string, direction: SortDirectionsT) => void
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -44,7 +44,7 @@ export function useTableData<T extends { [key: string]: any }>(options: UseTable
|
|
|
44
44
|
schemaState.value = 'loading'
|
|
45
45
|
|
|
46
46
|
// Get the data safely
|
|
47
|
-
const dataValue = options.data
|
|
47
|
+
const dataValue = toValue(options.data) || []
|
|
48
48
|
|
|
49
49
|
// Get the schema from useBglSchema
|
|
50
50
|
const schema = useBglSchema<T>({
|
|
@@ -100,6 +100,9 @@ export function useTableData<T extends { [key: string]: any }>(options: UseTable
|
|
|
100
100
|
const computedSchema = computed(() => resolvedSchema.value)
|
|
101
101
|
|
|
102
102
|
function transform(rowData: T): TransformedData<T> {
|
|
103
|
+
// TODO: only use type casting in the return statement
|
|
104
|
+
// TODO: replace assignments with Object.assign(transformed, {[key]: value})
|
|
105
|
+
|
|
103
106
|
const transformed = { ...rowData } as TransformedData<T>
|
|
104
107
|
const schemaFields = computedSchema.value.filter((f: any) => f.id)
|
|
105
108
|
|
|
@@ -150,16 +153,14 @@ export function useTableData<T extends { [key: string]: any }>(options: UseTable
|
|
|
150
153
|
|
|
151
154
|
const computedData = computed(() => {
|
|
152
155
|
// Get the data safely
|
|
153
|
-
const currentData = options.data
|
|
156
|
+
const currentData = toValue(options.data) || []
|
|
154
157
|
|
|
155
158
|
// If there's no data, return an empty array
|
|
156
159
|
if (!Array.isArray(currentData) || currentData.length === 0) {
|
|
157
160
|
return []
|
|
158
161
|
}
|
|
159
162
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (!sortField.value || useServerSortValue === true) {
|
|
163
|
+
if (!sortField.value || toValue(options.useServerSort) === true) {
|
|
163
164
|
return currentData.map(transform)
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { UploadInputProps } from '@bagelink/vue'
|
|
3
|
-
import { Btn, IMAGE_FORMATS_REGEXP, Icon, Card, Image, pathKeyToURL } from '@bagelink/vue'
|
|
4
|
-
import {
|
|
5
|
-
import { toValue } from 'vue'
|
|
3
|
+
import { Btn, IMAGE_FORMATS_REGEXP, Icon, Card, Image, pathKeyToURL, Loading } from '@bagelink/vue'
|
|
4
|
+
import { onMounted } from 'vue'
|
|
6
5
|
import { useFileUpload } from './useFileUpload'
|
|
7
6
|
|
|
8
7
|
const props = withDefaults(defineProps<UploadInputProps>(), {
|
|
9
8
|
height: '215px',
|
|
10
9
|
theme: 'dropzone',
|
|
11
|
-
accept: '*'
|
|
10
|
+
accept: '*',
|
|
12
11
|
})
|
|
13
12
|
|
|
14
13
|
const emit = defineEmits(['update:modelValue', 'addFileStart'])
|
|
@@ -18,15 +17,23 @@ const {
|
|
|
18
17
|
pathKeys,
|
|
19
18
|
removeFile,
|
|
20
19
|
flushQueue,
|
|
21
|
-
fileToUrl,
|
|
22
20
|
addFile,
|
|
23
21
|
browse,
|
|
24
|
-
pk
|
|
22
|
+
pk,
|
|
25
23
|
} = useFileUpload({
|
|
26
24
|
disabled: props.disabled,
|
|
27
25
|
dirPath: props.dirPath,
|
|
28
26
|
multiple: props.multiple,
|
|
29
|
-
accept: props.accept
|
|
27
|
+
accept: props.accept,
|
|
28
|
+
namespace: props.id,
|
|
29
|
+
onFileQueued: async () => {
|
|
30
|
+
await flushQueue()
|
|
31
|
+
updateModelValue()
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
onMounted(() => {
|
|
36
|
+
if (props.modelValue) pk.value = [props.modelValue].flat()
|
|
30
37
|
})
|
|
31
38
|
|
|
32
39
|
const isImage = (str: string) => IMAGE_FORMATS_REGEXP.test(str)
|
|
@@ -39,31 +46,24 @@ function handleDrag(e: DragEvent, isDragging = false) {
|
|
|
39
46
|
if (!props.disabled) isDragOver = isDragging
|
|
40
47
|
}
|
|
41
48
|
|
|
49
|
+
function updateModelValue() {
|
|
50
|
+
if (props.multiple) emit('update:modelValue', pathKeys.value)
|
|
51
|
+
else emit('update:modelValue', pathKeys.value[0] || undefined)
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
async function handleDrop(e: DragEvent) {
|
|
43
55
|
if (props.disabled) return
|
|
44
56
|
e.preventDefault()
|
|
45
57
|
e.stopPropagation()
|
|
46
58
|
emit('addFileStart')
|
|
47
59
|
addFile(e.dataTransfer?.files)
|
|
48
|
-
await flushQueue()
|
|
49
|
-
// emit('update:modelValue', pathKeys.value)
|
|
50
60
|
isDragOver = false
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
59
|
-
if (`${newVal}` === `${oldVal}`) return
|
|
60
|
-
if (newVal === undefined) return
|
|
61
|
-
if (Array.isArray(newVal)) {
|
|
62
|
-
pk.value = newVal
|
|
63
|
-
} else {
|
|
64
|
-
pk.value = [newVal]
|
|
65
|
-
}
|
|
66
|
-
}, { immediate: true, debounce: 500 })
|
|
63
|
+
function fileName(pathKey: string) {
|
|
64
|
+
if (!pathKey || typeof pathKey !== 'string') return 'file'
|
|
65
|
+
return pathKey.split('/').pop() || 'file'
|
|
66
|
+
}
|
|
67
67
|
</script>
|
|
68
68
|
|
|
69
69
|
<template>
|
|
@@ -108,7 +108,7 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
108
108
|
flat
|
|
109
109
|
thin
|
|
110
110
|
:href="pathKeyToURL(path_key)"
|
|
111
|
-
:download="path_key
|
|
111
|
+
:download="fileName(path_key)"
|
|
112
112
|
/>
|
|
113
113
|
<div class="flex gap-025 rounded pe-1 ps-05 py-025 bg-gray-80 -my-1 ">
|
|
114
114
|
<Icon icon="draft" :size="1.5" />
|
|
@@ -116,7 +116,7 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
116
116
|
v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
|
|
117
117
|
class="ellipsis-1 word-break-all h-20 m-0 color-black txt16"
|
|
118
118
|
>
|
|
119
|
-
{{ path_key
|
|
119
|
+
{{ fileName(path_key) }}
|
|
120
120
|
</p>
|
|
121
121
|
</div>
|
|
122
122
|
</div>
|
|
@@ -161,7 +161,7 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
161
161
|
/>
|
|
162
162
|
<Icon v-else icon="description" class="multi-preview" />
|
|
163
163
|
<p class="m-0">
|
|
164
|
-
{{ path_key
|
|
164
|
+
{{ fileName(path_key) }}
|
|
165
165
|
</p>
|
|
166
166
|
<Btn
|
|
167
167
|
thin
|
|
@@ -177,12 +177,12 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
177
177
|
class="multi-image-item-preview"
|
|
178
178
|
:class="{ 'bgl_fill-image': fill }"
|
|
179
179
|
>
|
|
180
|
-
<
|
|
180
|
+
<img
|
|
181
181
|
v-if="isImage(file.file.type)"
|
|
182
182
|
class="multi-preview"
|
|
183
|
-
:src="
|
|
183
|
+
:src="file.url"
|
|
184
184
|
alt=""
|
|
185
|
-
|
|
185
|
+
>
|
|
186
186
|
<Icon v-else icon="description" class="multi-preview" />
|
|
187
187
|
<p class="no-margin multi-preview-txt">
|
|
188
188
|
{{ file.name }}
|
|
@@ -232,7 +232,7 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
232
232
|
thin
|
|
233
233
|
icon="download"
|
|
234
234
|
:href="pathKeyToURL(path_key)"
|
|
235
|
-
:download="path_key
|
|
235
|
+
:download="fileName(path_key)"
|
|
236
236
|
/>
|
|
237
237
|
</div>
|
|
238
238
|
<div v-if="isImage(path_key)" class="h-100">
|
|
@@ -259,25 +259,13 @@ watchDebounced(() => props.modelValue, (newVal, oldVal) => {
|
|
|
259
259
|
class="single-image-item-preview"
|
|
260
260
|
:class="{ 'bgl_fill-image': fill }"
|
|
261
261
|
>
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
:style="{ '--p': file.progress }"
|
|
265
|
-
style="--b: 2px"
|
|
266
|
-
:class="{ complete: file.progress === 100 }"
|
|
267
|
-
>
|
|
268
|
-
<span v-if="file.progress < 100" class="progress">
|
|
269
|
-
{{ file.progress.toFixed(0) }}
|
|
270
|
-
</span>
|
|
271
|
-
<Icon class="success" icon="check_circle" />
|
|
272
|
-
</div>
|
|
273
|
-
<Image
|
|
262
|
+
<Loading type="bar" :progress="file.progress" class="absolute bottom-05 end start w-100px mx-auto" />
|
|
263
|
+
<img
|
|
274
264
|
v-if="isImage(file.file.type)"
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
:src="fileToUrl(file.file)"
|
|
265
|
+
class="single-preview opacity-5"
|
|
266
|
+
:src="file.url"
|
|
279
267
|
alt=""
|
|
280
|
-
|
|
268
|
+
>
|
|
281
269
|
</div>
|
|
282
270
|
</div>
|
|
283
271
|
</slot>
|
|
@@ -35,13 +35,16 @@
|
|
|
35
35
|
margin: 0.5rem !important;
|
|
36
36
|
background: var(--bgl-popup-bg);
|
|
37
37
|
padding: 0;
|
|
38
|
-
padding-inline-end:
|
|
38
|
+
padding-inline-end: 1rem;
|
|
39
|
+
padding-inline-start: 0.25rem;
|
|
39
40
|
text-align: start;
|
|
40
41
|
color: var(--input-color);
|
|
41
42
|
display: grid;
|
|
42
43
|
grid-template-columns: auto 1fr 22px;
|
|
43
|
-
gap:
|
|
44
|
+
gap: 0.5rem;
|
|
44
45
|
align-items: center;
|
|
46
|
+
height: var(--btn-height);
|
|
47
|
+
font-size: var(--label-font-size);
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
.multi-image-item-preview p {
|
|
@@ -51,9 +54,10 @@
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
.multi-preview {
|
|
54
|
-
width: 40px;
|
|
55
|
-
height:
|
|
56
|
-
|
|
57
|
+
/* width: 40px; */
|
|
58
|
+
height: calc(var(--btn-height) - 0.5rem);
|
|
59
|
+
max-width: calc(var(--btn-height) - 0.5rem);
|
|
60
|
+
border-radius: calc(var(--input-border-radius) / 2);
|
|
57
61
|
object-fit: cover;
|
|
58
62
|
background: var(--bgl-gray-light);
|
|
59
63
|
text-align: center !important;
|
|
@@ -92,14 +96,13 @@
|
|
|
92
96
|
}
|
|
93
97
|
|
|
94
98
|
.single-preview {
|
|
95
|
-
border-radius: var(--input-border-radius);
|
|
96
99
|
margin: 1rem;
|
|
97
100
|
padding: 0px;
|
|
98
|
-
min-height: calc(100% - 2rem);
|
|
99
101
|
height: calc(100% - 2rem);
|
|
100
|
-
|
|
102
|
+
max-height: calc(100% - 2rem);
|
|
101
103
|
background: var(--bgl-gray-light);
|
|
102
|
-
width:
|
|
104
|
+
max-width: calc(100% - 2rem);
|
|
105
|
+
object-fit: contain;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
.single-image-item-preview:hover::after {
|
|
@@ -8,11 +8,15 @@ interface UseFileUploadProps {
|
|
|
8
8
|
dirPath?: string
|
|
9
9
|
accept?: string
|
|
10
10
|
disabled?: boolean
|
|
11
|
+
namespace?: string
|
|
12
|
+
onFileQueued?: (files: QueueFile[]) => void
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
14
16
|
files.setBaseUrl(useBagel().host)
|
|
15
17
|
|
|
18
|
+
const namespace = props.namespace || 'default'
|
|
19
|
+
|
|
16
20
|
const fileQueue = ref<QueueFile[]>([])
|
|
17
21
|
const storageFiles = ref<BglFile[]>([])
|
|
18
22
|
const pk = ref<string[]>([])
|
|
@@ -40,12 +44,22 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const newQueueFiles = filesToAdd.map(f => ({
|
|
47
|
+
url: fileToUrl(f),
|
|
43
48
|
name: f.name,
|
|
44
49
|
file: f,
|
|
45
|
-
progress: 0
|
|
50
|
+
progress: 0,
|
|
51
|
+
namespace
|
|
46
52
|
}))
|
|
53
|
+
if (props.multiple) {
|
|
54
|
+
fileQueue.value.push(...newQueueFiles)
|
|
55
|
+
} else {
|
|
56
|
+
fileQueue.value = newQueueFiles
|
|
57
|
+
}
|
|
47
58
|
|
|
48
|
-
|
|
59
|
+
// Call the onFilesQueued callback if provided
|
|
60
|
+
if (props.onFileQueued && newQueueFiles.length > 0) {
|
|
61
|
+
props.onFileQueued(newQueueFiles)
|
|
62
|
+
}
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
const removeFile = async (pathKeyOrFile: string | File | QueueFile) => {
|
|
@@ -64,7 +78,15 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
64
78
|
console.error('Error deleting file:', error)
|
|
65
79
|
}
|
|
66
80
|
} else if (pathKeyOrFile) {
|
|
67
|
-
|
|
81
|
+
// For File or QueueFile, check if it's in our queue for this namespace
|
|
82
|
+
const fileToRemove = pathKeyOrFile instanceof File
|
|
83
|
+
? { name: pathKeyOrFile.name }
|
|
84
|
+
: pathKeyOrFile
|
|
85
|
+
|
|
86
|
+
const index = fileQueue.value.findIndex(queueFile => queueFile.file.name === fileToRemove.name
|
|
87
|
+
&& queueFile.namespace === namespace
|
|
88
|
+
)
|
|
89
|
+
|
|
68
90
|
if (index !== -1) {
|
|
69
91
|
fileQueue.value.splice(index, 1)
|
|
70
92
|
}
|
|
@@ -72,7 +94,10 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
72
94
|
}
|
|
73
95
|
|
|
74
96
|
const flushQueue = async () => {
|
|
75
|
-
|
|
97
|
+
// Only process files in the current namespace
|
|
98
|
+
const namespaceQueue = fileQueue.value.filter(file => file.namespace === namespace)
|
|
99
|
+
|
|
100
|
+
for (const file of namespaceQueue) {
|
|
76
101
|
file.uploading = true
|
|
77
102
|
|
|
78
103
|
// If not multiple, replace the existing file
|
|
@@ -85,7 +110,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
85
110
|
onUploadProgress: (e: ProgressEvent) => {
|
|
86
111
|
file.progress = (e.loaded / e.total) * 100 - 1
|
|
87
112
|
},
|
|
88
|
-
dirPath: props.dirPath
|
|
113
|
+
dirPath: props.dirPath
|
|
89
114
|
})
|
|
90
115
|
pk.value.push(data.path_key)
|
|
91
116
|
} catch (error) {
|
|
@@ -93,12 +118,12 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
93
118
|
}
|
|
94
119
|
}
|
|
95
120
|
|
|
96
|
-
// Clear the
|
|
97
|
-
fileQueue.value =
|
|
121
|
+
// Clear only files in the current namespace from the queue
|
|
122
|
+
fileQueue.value = fileQueue.value.filter(file => file.namespace !== namespace)
|
|
98
123
|
}
|
|
99
124
|
|
|
100
125
|
// UI interaction
|
|
101
|
-
const browse = (
|
|
126
|
+
const browse = (autoFlush = false) => {
|
|
102
127
|
if (props.disabled) return
|
|
103
128
|
|
|
104
129
|
const input = document.createElement('input')
|
|
@@ -108,7 +133,7 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
108
133
|
|
|
109
134
|
input.onchange = (e: Event) => {
|
|
110
135
|
addFile((e.target as HTMLInputElement).files)
|
|
111
|
-
if (
|
|
136
|
+
if (autoFlush) {
|
|
112
137
|
flushQueue()
|
|
113
138
|
}
|
|
114
139
|
}
|
|
@@ -140,5 +165,6 @@ export function useFileUpload(props: UseFileUploadProps = {}) {
|
|
|
140
165
|
flushQueue,
|
|
141
166
|
addFile,
|
|
142
167
|
browse,
|
|
168
|
+
namespace
|
|
143
169
|
}
|
|
144
170
|
}
|
|
@@ -5,7 +5,6 @@ export { default as ColorInput } from './ColorInput.vue'
|
|
|
5
5
|
export { default as DateInput } from './DateInput.vue'
|
|
6
6
|
export { default as DatePicker } from './DatePicker.vue'
|
|
7
7
|
export { default as EmailInput } from './EmailInput.vue'
|
|
8
|
-
export { default as FileUpload } from './FileUpload.vue'
|
|
9
8
|
export { default as JSONInput } from './JSONInput.vue'
|
|
10
9
|
export { default as NumberInput } from './NumberInput.vue'
|
|
11
10
|
export { default as OTP } from './OTP.vue'
|