@bagelink/vue 0.0.363 → 0.0.378
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/Alert.vue.d.ts.map +1 -1
- package/dist/components/Card.vue.d.ts +2 -0
- package/dist/components/Card.vue.d.ts.map +1 -1
- package/dist/components/form/BglField.vue.d.ts.map +1 -1
- package/dist/components/form/BglForm.vue.d.ts +3 -0
- package/dist/components/form/BglForm.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts +4 -2
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RichText.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/layout/SidebarMenu.vue.d.ts.map +1 -1
- package/dist/index.cjs +209 -167
- package/dist/index.mjs +209 -167
- package/dist/style.css +138 -81
- package/dist/utils/BagelFormUtils.d.ts +10 -0
- package/dist/utils/BagelFormUtils.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Alert.vue +1 -1
- package/src/components/Card.vue +51 -23
- package/src/components/form/BglField.vue +65 -36
- package/src/components/form/BglForm.vue +64 -60
- package/src/components/form/inputs/DatePicker.vue +15 -18
- package/src/components/form/inputs/FileUpload.vue +71 -90
- package/src/components/form/inputs/RichText.vue +70 -43
- package/src/components/form/inputs/SelectInput.vue +1 -1
- package/src/components/form/inputs/TextInput.vue +4 -0
- package/src/components/layout/SidebarMenu.vue +39 -20
- package/src/styles/text.css +1 -1
- package/src/utils/BagelFormUtils.ts +14 -0
|
@@ -1,58 +1,87 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
<component
|
|
3
|
+
:required="field.required"
|
|
4
|
+
v-bind="bindAttrs(field?.attrs || {}, fieldData, modelValue)"
|
|
5
|
+
:class="classify(fieldData, modelValue, field.class, field.attrs?.class)"
|
|
6
|
+
v-if="vIf"
|
|
7
|
+
:is="is"
|
|
8
|
+
:label="field.label"
|
|
9
|
+
:id="field.id"
|
|
10
|
+
:placeholder="field.placeholder || field.label"
|
|
11
|
+
v-model="fieldData"
|
|
12
|
+
:defaultValue="field.defaultValue"
|
|
13
|
+
:options="
|
|
14
|
+
bindAttrs({ options: field.options }, fieldData, modelValue).options
|
|
15
|
+
"
|
|
16
|
+
:helptext="field.helptext"
|
|
17
|
+
@update:modelValue="($event: any) => field?.onUpdate?.($event, formData)">
|
|
18
|
+
{{ field.transform?.(fieldData, modelValue) || fieldData || '' }}
|
|
19
|
+
<BglField
|
|
20
|
+
v-model="formData"
|
|
21
|
+
v-for="(child, ii) in field.children"
|
|
22
|
+
:key="child.id || ii"
|
|
23
|
+
:field="child" />
|
|
24
|
+
</component>
|
|
10
25
|
</template>
|
|
11
26
|
|
|
12
27
|
<script lang="ts" setup>
|
|
13
28
|
import {
|
|
14
|
-
|
|
29
|
+
type Field,
|
|
30
|
+
bindAttrs,
|
|
31
|
+
classify,
|
|
32
|
+
SelectInput,
|
|
33
|
+
TextInput,
|
|
34
|
+
ToggleInput,
|
|
35
|
+
CheckInput,
|
|
36
|
+
RichText,
|
|
15
37
|
} from '@bagelink/vue';
|
|
16
38
|
|
|
17
|
-
const props = withDefaults(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
39
|
+
const props = withDefaults(
|
|
40
|
+
defineProps<{
|
|
41
|
+
field: Field;
|
|
42
|
+
modelValue: Record<string, any>;
|
|
43
|
+
}>(),
|
|
44
|
+
{
|
|
45
|
+
modelValue: () => ({}),
|
|
46
|
+
}
|
|
47
|
+
);
|
|
23
48
|
|
|
24
49
|
const is = $computed(() => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
if (props.field.$el === 'text') return TextInput;
|
|
51
|
+
if (props.field.$el === 'select') return SelectInput;
|
|
52
|
+
if (props.field.$el === 'toggle') return ToggleInput;
|
|
53
|
+
if (props.field.$el === 'check') return CheckInput;
|
|
54
|
+
if (props.field.$el === 'richtext') return RichText;
|
|
55
|
+
return props.field.$el || 'div';
|
|
30
56
|
});
|
|
31
57
|
|
|
32
58
|
const emit = defineEmits(['update:modelValue']);
|
|
33
59
|
|
|
34
60
|
const formData = $computed({
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
get: () => props.modelValue,
|
|
62
|
+
set: (val: any) => emit('update:modelValue', val),
|
|
37
63
|
});
|
|
38
64
|
|
|
39
65
|
const fieldData = $computed({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
66
|
+
set: (val: any) => {
|
|
67
|
+
if (!props.field.id) return;
|
|
68
|
+
const data = { ...props.modelValue } || {};
|
|
69
|
+
data[props.field.id] = val;
|
|
70
|
+
emit('update:modelValue', data);
|
|
71
|
+
},
|
|
72
|
+
get: () => {
|
|
73
|
+
if (props.field.id) return props.modelValue[props.field.id];
|
|
74
|
+
return props.field.defaultValue || '';
|
|
75
|
+
},
|
|
47
76
|
});
|
|
48
77
|
|
|
49
78
|
const vIf = $computed(() => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
79
|
+
if (props.field['v-if'] === undefined) return true;
|
|
80
|
+
if (typeof props.field['v-if'] === 'boolean') return props.field['v-if'];
|
|
81
|
+
if (typeof props.field['v-if'] === 'string') return true;
|
|
82
|
+
if (typeof props.field['v-if'] === 'function') {
|
|
83
|
+
return props.field['v-if']?.(fieldData, formData);
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
57
86
|
});
|
|
58
87
|
</script>
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
<template v-if="id">
|
|
3
|
+
<BglField
|
|
4
|
+
v-for="(field, i) in schema"
|
|
5
|
+
:key="field.id || `${i}p`"
|
|
6
|
+
:field="field"
|
|
7
|
+
v-model="data" />
|
|
8
|
+
</template>
|
|
9
|
+
<form
|
|
10
|
+
v-else-if="!slots.success || status !== 'success'"
|
|
11
|
+
ref="form"
|
|
12
|
+
@submit.prevent="runSubmit">
|
|
13
|
+
<Title tag="h4" :label="label" v-if="label" />
|
|
14
|
+
<BglField
|
|
15
|
+
v-for="(field, i) in schema"
|
|
16
|
+
:key="field.id || `${i}p`"
|
|
17
|
+
:field="field"
|
|
18
|
+
v-model="data" />
|
|
19
|
+
<slot name="submit" />
|
|
20
|
+
</form>
|
|
21
|
+
<slot v-if="status === 'success'" name="success" />
|
|
22
|
+
<slot v-if="status === 'error'" name="error" />
|
|
12
23
|
</template>
|
|
13
24
|
|
|
14
25
|
<script lang="ts" setup>
|
|
15
26
|
import { useSlots } from 'vue';
|
|
16
|
-
import {
|
|
17
|
-
useModal, BglField, Title,
|
|
18
|
-
} from '@bagelink/vue';
|
|
27
|
+
import { useModal, BglField, Title } from '@bagelink/vue';
|
|
19
28
|
|
|
20
29
|
import { type BglFormSchemaT } from '@bagelink/vue';
|
|
21
30
|
|
|
@@ -24,17 +33,18 @@ const slots = useSlots();
|
|
|
24
33
|
const { showModal } = useModal();
|
|
25
34
|
|
|
26
35
|
const props = withDefaults(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
defineProps<{
|
|
37
|
+
label?: string;
|
|
38
|
+
id?: string;
|
|
39
|
+
schema: BglFormSchemaT<any>;
|
|
40
|
+
modelValue?: Record<string, any>;
|
|
41
|
+
onDelete?: (id: string) => void;
|
|
42
|
+
onSubmit?: (data: any) => void;
|
|
43
|
+
status?: FormStatus;
|
|
44
|
+
}>(),
|
|
45
|
+
{
|
|
46
|
+
modelValue: () => ({}),
|
|
47
|
+
}
|
|
38
48
|
);
|
|
39
49
|
|
|
40
50
|
const instAt = new Date();
|
|
@@ -43,15 +53,15 @@ let formData = $ref(props.modelValue);
|
|
|
43
53
|
const emit = defineEmits(['update:modelValue', 'submit', 'dirty']);
|
|
44
54
|
let isDirty = $ref(false);
|
|
45
55
|
const data = $computed({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
set: (val: any) => {
|
|
57
|
+
if (timeSinceInst() > 100) {
|
|
58
|
+
emit('dirty');
|
|
59
|
+
isDirty = true;
|
|
60
|
+
}
|
|
61
|
+
formData = val;
|
|
62
|
+
emit('update:modelValue', val);
|
|
63
|
+
},
|
|
64
|
+
get: () => props.modelValue || formData,
|
|
55
65
|
});
|
|
56
66
|
const form = $ref<HTMLFormElement>();
|
|
57
67
|
|
|
@@ -61,38 +71,32 @@ const clearForm = () => Object.assign(data, {});
|
|
|
61
71
|
|
|
62
72
|
type FormStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
63
73
|
|
|
64
|
-
let formStatus = $ref<FormStatus>('idle');
|
|
65
|
-
|
|
66
74
|
const runSubmit = () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
formStatus = 'success';
|
|
73
|
-
} catch (e) {
|
|
74
|
-
formStatus = 'error';
|
|
75
|
-
}
|
|
75
|
+
const isValid = validateForm();
|
|
76
|
+
if (!isValid) return;
|
|
77
|
+
props.onSubmit?.(data);
|
|
78
|
+
// emit('submit', data);
|
|
79
|
+
clearForm();
|
|
76
80
|
};
|
|
77
81
|
|
|
78
82
|
const i18nT = (val: string) => val;
|
|
79
83
|
|
|
80
84
|
const deleteItem = () => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
showModal(
|
|
86
|
+
{
|
|
87
|
+
class: 'small-modal',
|
|
88
|
+
title: i18nT('Are you sure?'),
|
|
89
|
+
actions: [
|
|
90
|
+
{
|
|
91
|
+
value: 'Confirm',
|
|
92
|
+
color: 'red',
|
|
93
|
+
onClick: () => props.onDelete?.(data.value.id),
|
|
94
|
+
},
|
|
95
|
+
{ value: 'Cancel', color: 'gray' },
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
{ default: i18nT('form.deleteMessage') }
|
|
99
|
+
);
|
|
96
100
|
};
|
|
97
101
|
|
|
98
102
|
defineExpose({ validateForm, deleteItem, isDirty });
|
|
@@ -100,6 +104,6 @@ defineExpose({ validateForm, deleteItem, isDirty });
|
|
|
100
104
|
|
|
101
105
|
<style>
|
|
102
106
|
.del-top {
|
|
103
|
-
|
|
107
|
+
transform: translateY(-2.6rem);
|
|
104
108
|
}
|
|
105
109
|
</style>
|
|
@@ -8,28 +8,20 @@
|
|
|
8
8
|
:highlight-week-days="[6]"
|
|
9
9
|
:enable-time-picker="false"
|
|
10
10
|
:month-change-on-scroll="false"
|
|
11
|
-
v-bind="options"
|
|
12
|
-
>
|
|
11
|
+
v-bind="options">
|
|
13
12
|
<template #action-buttons />
|
|
14
13
|
<template #action-preview />
|
|
15
14
|
</VDatepicker>
|
|
16
15
|
</div>
|
|
17
|
-
<div
|
|
18
|
-
|
|
19
|
-
v-if="showTimeWrap"
|
|
20
|
-
>
|
|
21
|
-
<template
|
|
22
|
-
v-for="hr in hours"
|
|
23
|
-
:key="hr"
|
|
24
|
-
>
|
|
16
|
+
<div class="time-wrap" v-if="showTimeWrap">
|
|
17
|
+
<template v-for="hr in hours" :key="hr">
|
|
25
18
|
<input
|
|
26
19
|
type="radio"
|
|
27
|
-
:id="`${hr}_${
|
|
28
|
-
:name="
|
|
20
|
+
:id="`${hr}_${id}`"
|
|
21
|
+
:name="label"
|
|
29
22
|
:value="hr"
|
|
30
|
-
v-model="selectedHour"
|
|
31
|
-
>
|
|
32
|
-
<label :for="`${hr}_${name}`">{{ hr }}</label>
|
|
23
|
+
v-model="selectedHour" />
|
|
24
|
+
<label :for="`${hr}_${id}`">{{ hr }}</label>
|
|
33
25
|
</template>
|
|
34
26
|
</div>
|
|
35
27
|
</div>
|
|
@@ -39,7 +31,12 @@
|
|
|
39
31
|
import VDatepicker from '@vuepic/vue-datepicker';
|
|
40
32
|
import '@vuepic/vue-datepicker/dist/main.css';
|
|
41
33
|
|
|
42
|
-
defineProps<{
|
|
34
|
+
defineProps<{
|
|
35
|
+
label?: string;
|
|
36
|
+
id?: string;
|
|
37
|
+
options?: Record<string, any>;
|
|
38
|
+
showTimeWrap?: boolean;
|
|
39
|
+
}>();
|
|
43
40
|
const selectedDate = $ref(null);
|
|
44
41
|
const selectedHour = $ref();
|
|
45
42
|
|
|
@@ -80,7 +77,7 @@ const hours = Array.from({ length: 18 }, (_, index) => {
|
|
|
80
77
|
border: 1px solid var(--bgl-primary);
|
|
81
78
|
}
|
|
82
79
|
|
|
83
|
-
.time-wrap input[type=
|
|
80
|
+
.time-wrap input[type='radio']:checked + label {
|
|
84
81
|
background: var(--bgl-primary);
|
|
85
82
|
color: var(--bgl-white);
|
|
86
83
|
}
|
|
@@ -130,7 +127,7 @@ const hours = Array.from({ length: 18 }, (_, index) => {
|
|
|
130
127
|
margin-bottom: -10px;
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
.dp__calendar_row>div:last-child {
|
|
130
|
+
.dp__calendar_row > div:last-child {
|
|
134
131
|
pointer-events: none;
|
|
135
132
|
}
|
|
136
133
|
|
|
@@ -9,21 +9,13 @@
|
|
|
9
9
|
@drop="drop"
|
|
10
10
|
@dragleave="dragleave"
|
|
11
11
|
class="fileUploadWrap"
|
|
12
|
-
:class="{
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class="imagePreviewWrap"
|
|
20
|
-
v-if="!multiple"
|
|
21
|
-
>
|
|
22
|
-
<img
|
|
23
|
-
class="preview"
|
|
24
|
-
:src="file.url"
|
|
25
|
-
alt=""
|
|
26
|
-
>
|
|
12
|
+
:class="{
|
|
13
|
+
fileDropZone: !storageFiles.length && !fileQueue.length,
|
|
14
|
+
dragover: isDragOver,
|
|
15
|
+
}">
|
|
16
|
+
<template v-for="file in storageFiles" :key="file.id">
|
|
17
|
+
<div class="imagePreviewWrap" v-if="!multiple">
|
|
18
|
+
<img class="preview" :src="file.url" alt="" />
|
|
27
19
|
</div>
|
|
28
20
|
<div class="previewName">
|
|
29
21
|
<img
|
|
@@ -31,8 +23,7 @@
|
|
|
31
23
|
v-if="multiple"
|
|
32
24
|
class="preview"
|
|
33
25
|
:src="file.url"
|
|
34
|
-
alt=""
|
|
35
|
-
>
|
|
26
|
+
alt="" />
|
|
36
27
|
<p class="no-margin">
|
|
37
28
|
{{ file.name }}
|
|
38
29
|
</p>
|
|
@@ -41,23 +32,12 @@
|
|
|
41
32
|
@click.stop="removeFile(file)"
|
|
42
33
|
flat
|
|
43
34
|
icon="delete"
|
|
44
|
-
color="red"
|
|
45
|
-
/>
|
|
35
|
+
color="red" />
|
|
46
36
|
</div>
|
|
47
37
|
</template>
|
|
48
|
-
<template
|
|
49
|
-
v-
|
|
50
|
-
|
|
51
|
-
>
|
|
52
|
-
<div
|
|
53
|
-
class="imagePreviewWrap"
|
|
54
|
-
v-if="!multiple"
|
|
55
|
-
>
|
|
56
|
-
<img
|
|
57
|
-
class="preview"
|
|
58
|
-
:src="fileToUrl(fileQ.file)"
|
|
59
|
-
alt=""
|
|
60
|
-
>
|
|
38
|
+
<template v-for="fileQ in fileQueue" :key="fileQ.file">
|
|
39
|
+
<div class="imagePreviewWrap" v-if="!multiple">
|
|
40
|
+
<img class="preview" :src="fileToUrl(fileQ.file)" alt="" />
|
|
61
41
|
</div>
|
|
62
42
|
<div class="previewName">
|
|
63
43
|
<img
|
|
@@ -65,8 +45,7 @@
|
|
|
65
45
|
v-if="multiple"
|
|
66
46
|
class="preview"
|
|
67
47
|
:src="fileToUrl(fileQ.file)"
|
|
68
|
-
alt=""
|
|
69
|
-
>
|
|
48
|
+
alt="" />
|
|
70
49
|
<p class="no-margin">
|
|
71
50
|
{{ fileQ.name }}
|
|
72
51
|
</p>
|
|
@@ -74,18 +53,11 @@
|
|
|
74
53
|
class="pie"
|
|
75
54
|
:style="`--p:${fileQ.progress}`"
|
|
76
55
|
style="--b: 2px"
|
|
77
|
-
:class="{ complete: fileQ.progress === 100 }"
|
|
78
|
-
|
|
79
|
-
<span
|
|
80
|
-
class="progress"
|
|
81
|
-
v-if="fileQ.progress < 100"
|
|
82
|
-
>
|
|
56
|
+
:class="{ complete: fileQ.progress === 100 }">
|
|
57
|
+
<span class="progress" v-if="fileQ.progress < 100">
|
|
83
58
|
{{ `${fileQ.progress.toFixed(0)}` }}
|
|
84
59
|
</span>
|
|
85
|
-
<MaterialIcon
|
|
86
|
-
class="success"
|
|
87
|
-
icon="check"
|
|
88
|
-
/>
|
|
60
|
+
<MaterialIcon class="success" icon="check" />
|
|
89
61
|
</div>
|
|
90
62
|
</div>
|
|
91
63
|
</template>
|
|
@@ -95,9 +67,7 @@
|
|
|
95
67
|
|
|
96
68
|
<script setup lang="ts">
|
|
97
69
|
import { watch } from 'vue';
|
|
98
|
-
import {
|
|
99
|
-
Btn, type StorageFile, useBagel, MaterialIcon,
|
|
100
|
-
} from '@bagelink/vue';
|
|
70
|
+
import { Btn, type StorageFile, useBagel, MaterialIcon } from '@bagelink/vue';
|
|
101
71
|
|
|
102
72
|
const bagel = useBagel();
|
|
103
73
|
|
|
@@ -110,27 +80,36 @@ type QueueFile = {
|
|
|
110
80
|
};
|
|
111
81
|
|
|
112
82
|
const props = defineProps<{
|
|
113
|
-
label: string
|
|
114
|
-
multiple?: boolean
|
|
115
|
-
files?: StorageFile | StorageFile[]
|
|
83
|
+
label: string;
|
|
84
|
+
multiple?: boolean;
|
|
85
|
+
files?: StorageFile | StorageFile[];
|
|
116
86
|
deleteEndpoint?: string;
|
|
117
87
|
}>();
|
|
118
88
|
|
|
119
89
|
const file_ids = defineModel<string[] | string>('modelValue');
|
|
120
90
|
const storageFiles = $ref<StorageFile[]>([]);
|
|
121
91
|
|
|
122
|
-
const compareIds = (v1?: string[] | string, v2?: string[] | string) =>
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
92
|
+
const compareIds = (v1?: string[] | string, v2?: string[] | string) =>
|
|
93
|
+
[v1].flat().join(',') === [v2].flat().join(',');
|
|
94
|
+
|
|
95
|
+
watch(
|
|
96
|
+
() => props.files,
|
|
97
|
+
(newFiles) => {
|
|
98
|
+
if (newFiles) storageFiles.push(...[newFiles].flat());
|
|
99
|
+
},
|
|
100
|
+
{ immediate: true }
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
watch(
|
|
104
|
+
() => storageFiles,
|
|
105
|
+
(newFiles) => {
|
|
106
|
+
let idValue: string[] | string = '';
|
|
107
|
+
if (props.multiple) idValue = newFiles.map((f) => f.id || '');
|
|
108
|
+
else idValue = newFiles[0]?.id || '';
|
|
109
|
+
if (!compareIds(file_ids?.value, idValue)) file_ids.value = idValue;
|
|
110
|
+
},
|
|
111
|
+
{ deep: true }
|
|
112
|
+
);
|
|
134
113
|
|
|
135
114
|
const fileQueue = $ref<QueueFile[]>([]);
|
|
136
115
|
let isDragOver = $ref(false);
|
|
@@ -145,20 +124,20 @@ const removeFile = (file: StorageFile) => {
|
|
|
145
124
|
const index = storageFiles.indexOf(file);
|
|
146
125
|
storageFiles.splice(index, 1);
|
|
147
126
|
|
|
148
|
-
if (props.deleteEndpoint)
|
|
127
|
+
if (props.deleteEndpoint) {
|
|
128
|
+
void bagel.delete(`${props.deleteEndpoint}/${file.id}`);
|
|
129
|
+
}
|
|
149
130
|
};
|
|
150
131
|
|
|
151
132
|
const flushQueue = () => {
|
|
152
|
-
fileQueue.forEach(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
},
|
|
161
|
-
);
|
|
133
|
+
fileQueue.forEach(async (file, i) => {
|
|
134
|
+
if (!props.multiple) storageFiles.splice(0, 1);
|
|
135
|
+
const serverFile = await bagel.uploadFile<StorageFile>(file.file, {
|
|
136
|
+
onUploadProgress: (e: any) => (file.progress = e.progress * 100 - 1),
|
|
137
|
+
});
|
|
138
|
+
storageFiles.push(serverFile);
|
|
139
|
+
fileQueue.splice(i, 1);
|
|
140
|
+
});
|
|
162
141
|
};
|
|
163
142
|
|
|
164
143
|
const browse = () => {
|
|
@@ -168,7 +147,9 @@ const browse = () => {
|
|
|
168
147
|
input.onchange = (e: Event) => {
|
|
169
148
|
const target = e?.target as HTMLInputElement;
|
|
170
149
|
if (target?.files) {
|
|
171
|
-
Array.from(target.files).forEach((file: File) =>
|
|
150
|
+
Array.from(target.files).forEach((file: File) =>
|
|
151
|
+
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
152
|
+
);
|
|
172
153
|
}
|
|
173
154
|
flushQueue();
|
|
174
155
|
};
|
|
@@ -190,13 +171,9 @@ const dragover = (e: DragEvent) => {
|
|
|
190
171
|
const drop = (e: DragEvent) => {
|
|
191
172
|
preventDefault(e);
|
|
192
173
|
if (e.dataTransfer) {
|
|
193
|
-
Array
|
|
194
|
-
.
|
|
195
|
-
|
|
196
|
-
(file: File) => (
|
|
197
|
-
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
198
|
-
),
|
|
199
|
-
);
|
|
174
|
+
Array.from(e.dataTransfer.files).forEach((file: File) =>
|
|
175
|
+
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
176
|
+
);
|
|
200
177
|
}
|
|
201
178
|
isDragOver = false;
|
|
202
179
|
flushQueue();
|
|
@@ -222,7 +199,7 @@ const drop = (e: DragEvent) => {
|
|
|
222
199
|
display: grid;
|
|
223
200
|
grid-template-columns: 1fr 22px;
|
|
224
201
|
align-items: center;
|
|
225
|
-
|
|
202
|
+
padding-inline: 14px;
|
|
226
203
|
}
|
|
227
204
|
|
|
228
205
|
.previewName p {
|
|
@@ -258,7 +235,7 @@ img.preview {
|
|
|
258
235
|
}
|
|
259
236
|
|
|
260
237
|
.bagel-input .fileUploadWrap.fileDropZone:after {
|
|
261
|
-
content:
|
|
238
|
+
content: 'Drop files here or click to upload';
|
|
262
239
|
}
|
|
263
240
|
|
|
264
241
|
.pie {
|
|
@@ -271,18 +248,22 @@ img.preview {
|
|
|
271
248
|
}
|
|
272
249
|
|
|
273
250
|
.pie:before {
|
|
274
|
-
content:
|
|
251
|
+
content: '';
|
|
275
252
|
position: absolute;
|
|
276
253
|
border-radius: 50%;
|
|
277
254
|
inset: 0;
|
|
278
255
|
transition: all 0.2s ease-in-out;
|
|
279
256
|
background: conic-gradient(var(--bgl-primary) calc(var(--p) * 1%), #0000 0);
|
|
280
|
-
-webkit-mask: radial-gradient(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
257
|
+
-webkit-mask: radial-gradient(
|
|
258
|
+
farthest-side,
|
|
259
|
+
#0000 calc(99% - var(--b)),
|
|
260
|
+
#000 calc(100% - var(--b))
|
|
261
|
+
);
|
|
262
|
+
mask: radial-gradient(
|
|
263
|
+
farthest-side,
|
|
264
|
+
#0000 calc(99% - var(--b)),
|
|
265
|
+
#000 calc(100% - var(--b))
|
|
266
|
+
);
|
|
286
267
|
}
|
|
287
268
|
|
|
288
269
|
.pie .success {
|