@bagelink/vue 0.0.423 → 0.0.431
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/AccordionItem.vue.d.ts +3 -2
- package/dist/components/AccordionItem.vue.d.ts.map +1 -1
- package/dist/components/Alert.vue.d.ts +4 -1
- package/dist/components/Alert.vue.d.ts.map +1 -1
- package/dist/components/Avatar.vue.d.ts.map +1 -1
- package/dist/components/Carousel.vue.d.ts +8 -2
- package/dist/components/Carousel.vue.d.ts.map +1 -1
- package/dist/components/Modal.vue.d.ts.map +1 -1
- package/dist/components/TableSchema.vue.d.ts +2 -5
- package/dist/components/TableSchema.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts +4 -0
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/FileUpload.vue.d.ts +6 -2
- package/dist/components/form/inputs/FileUpload.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioPillsInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TextInput.vue.d.ts +0 -3
- package/dist/components/form/inputs/TextInput.vue.d.ts.map +1 -1
- package/dist/components/layout/Tabs.vue.d.ts +6 -2
- package/dist/components/layout/Tabs.vue.d.ts.map +1 -1
- package/dist/components/layout/TabsNav.vue.d.ts +6 -2
- package/dist/components/layout/TabsNav.vue.d.ts.map +1 -1
- package/dist/index.cjs +256 -155
- package/dist/index.mjs +257 -156
- package/dist/plugins/bagel.d.ts +3 -0
- package/dist/plugins/bagel.d.ts.map +1 -1
- package/dist/style.css +194 -172
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/lang.d.ts +7 -0
- package/dist/utils/lang.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/AccordionItem.vue +57 -43
- package/src/components/Alert.vue +4 -2
- package/src/components/Avatar.vue +1 -1
- package/src/components/Carousel.vue +2 -2
- package/src/components/Modal.vue +4 -2
- package/src/components/TableSchema.vue +19 -9
- package/src/components/form/inputs/DatePicker.vue +8 -2
- package/src/components/form/inputs/FileUpload.vue +54 -23
- package/src/components/form/inputs/RadioPillsInput.vue +5 -4
- package/src/components/form/inputs/SelectInput.vue +212 -204
- package/src/components/form/inputs/TextInput.vue +1 -1
- package/src/components/layout/Tabs.vue +14 -5
- package/src/components/layout/TabsNav.vue +40 -15
- package/src/plugins/bagel.ts +13 -4
- package/src/utils/index.ts +2 -0
- package/src/utils/lang.ts +39 -0
package/dist/utils/index.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export declare const iffer: (field: any, itemData: any) => any;
|
|
|
11
11
|
export declare const denullify: (itemData?: Record<string, any>, fieldID?: string) => any;
|
|
12
12
|
export { formatString } from './strings';
|
|
13
13
|
export * as bagelFormUtils from './BagelFormUtils';
|
|
14
|
+
export { useLang } from './lang';
|
|
14
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,eAAO,MAAM,QAAQ,OAAQ,MAAM,IAAI,yBAGtC,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,MAAM,GAAG,SAEjC,CAAC;AAEnB,eAAO,MAAM,QAAQ,SACd,MAAM,OAEP,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,kBAI1B,CAAC;AAEF,eAAO,MAAM,QAAQ,cAAe,MAAM,EAAE,WAG3C,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,QAIrE;AAED,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,UAKpE;AAED,wBAAgB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,OAS7F;AAED,eAAO,MAAM,KAAK,UAAW,GAAG,YAAY,GAAG,QAM9C,CAAC;AAEF,eAAO,MAAM,SAAS,cAAe,OAAO,MAAM,EAAE,GAAG,CAAC,YAAY,MAAM,QAAqD,CAAC;AAEhI,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,cAAc,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGtC,eAAO,MAAM,QAAQ,OAAQ,MAAM,IAAI,yBAGtC,CAAC;AAEF,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,MAAM,GAAG,SAEjC,CAAC;AAEnB,eAAO,MAAM,QAAQ,SACd,MAAM,OAEP,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,kBAI1B,CAAC;AAEF,eAAO,MAAM,QAAQ,cAAe,MAAM,EAAE,WAG3C,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,IAAI,QAIrE;AAED,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,UAKpE;AAED,wBAAgB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,OAS7F;AAED,eAAO,MAAM,KAAK,UAAW,GAAG,YAAY,GAAG,QAM9C,CAAC;AAEF,eAAO,MAAM,SAAS,cAAe,OAAO,MAAM,EAAE,GAAG,CAAC,YAAY,MAAM,QAAqD,CAAC;AAEhI,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,cAAc,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function useLang(): {
|
|
2
|
+
lang: import('vue').WritableComputedRef<string>;
|
|
3
|
+
$tdb: (langEl: Record<string, any>) => any;
|
|
4
|
+
availableLangs: import('vue').WritableComputedRef<string[]>;
|
|
5
|
+
defaultLang: import('vue').WritableComputedRef<string>;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=lang.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.d.ts","sourceRoot":"","sources":["../../src/utils/lang.ts"],"names":[],"mappings":"AAcA,wBAAgB,OAAO;;mBAMA,OAAO,MAAM,EAAE,GAAG,CAAC;;;EAkBzC"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
<div class="accordion-item">
|
|
3
|
+
<button
|
|
4
|
+
@click="toggle()"
|
|
5
|
+
:aria-expanded="open ? 'true' : 'false'"
|
|
6
|
+
class="accordion-head"
|
|
7
|
+
:aria-controls="`accordion-body-${id}`">
|
|
8
|
+
<span class="accordion-label">{{ label }}</span>
|
|
9
|
+
<slot name="head" />
|
|
10
|
+
<div class="accordion-icon" :class="{ open }">
|
|
11
|
+
<MaterialIcon icon="expand_more" />
|
|
12
|
+
</div>
|
|
13
|
+
</button>
|
|
14
|
+
<Transition name="expand">
|
|
15
|
+
<div
|
|
16
|
+
v-if="open"
|
|
17
|
+
class="accordion-body"
|
|
18
|
+
:id="`accordion-body-${id}`"
|
|
19
|
+
:aria-hidden="open ? 'false' : 'true'">
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
22
|
+
</Transition>
|
|
23
|
+
</div>
|
|
16
24
|
</template>
|
|
17
25
|
|
|
18
26
|
<script lang="ts" setup>
|
|
@@ -20,77 +28,83 @@ import { MaterialIcon } from '@bagelink/vue';
|
|
|
20
28
|
import { watch, inject } from 'vue';
|
|
21
29
|
|
|
22
30
|
const props = defineProps<{
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
label?: string;
|
|
32
|
+
id?: string;
|
|
25
33
|
}>();
|
|
26
34
|
let open = $ref(false);
|
|
27
35
|
|
|
28
36
|
const accordionState = inject('accordionState') as { openItem: string | null };
|
|
29
37
|
const id = props.id || Math.random().toString(36).substring(7);
|
|
30
38
|
|
|
31
|
-
watch(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
watch(
|
|
40
|
+
() => accordionState?.openItem,
|
|
41
|
+
(currentOpenId) => {
|
|
42
|
+
if (currentOpenId !== id) {
|
|
43
|
+
open = false;
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{ immediate: true }
|
|
47
|
+
);
|
|
36
48
|
|
|
37
49
|
function toggle() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
open = !open;
|
|
51
|
+
if (open && accordionState?.openItem) accordionState.openItem = id;
|
|
52
|
+
else if (accordionState?.openItem === id) accordionState.openItem = null;
|
|
41
53
|
}
|
|
42
54
|
</script>
|
|
43
55
|
|
|
44
56
|
<style scoped>
|
|
45
57
|
.accordion-item {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
border-bottom: 1px solid var(--border-color);
|
|
59
|
+
transition: all 0.2s;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
overflow: hidden;
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
.accordion-head {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
height: var(--input-height);
|
|
66
|
+
background: transparent;
|
|
67
|
+
display: flex;
|
|
68
|
+
width: 100%;
|
|
69
|
+
align-items: center;
|
|
70
|
+
justify-content: space-between;
|
|
71
|
+
border: none;
|
|
59
72
|
}
|
|
60
73
|
|
|
61
74
|
.accordion-icon {
|
|
62
|
-
|
|
75
|
+
transition: all 0.2s ease;
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
.accordion-icon.open {
|
|
66
|
-
|
|
79
|
+
transform: rotate(180deg);
|
|
67
80
|
}
|
|
68
81
|
|
|
69
82
|
.accordion-label {
|
|
70
|
-
|
|
83
|
+
font-weight: bold;
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
.accordion-head:hover .accordion-label {
|
|
74
|
-
|
|
87
|
+
text-decoration: underline;
|
|
75
88
|
}
|
|
76
89
|
|
|
77
|
-
.accordion-body {
|
|
90
|
+
.accordion-body {
|
|
91
|
+
}
|
|
78
92
|
</style>
|
|
79
93
|
|
|
80
94
|
<style>
|
|
81
95
|
.expand-enter-active,
|
|
82
96
|
.expand-leave-active {
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
transition: all 0.2s;
|
|
98
|
+
transition-delay: 0ms;
|
|
85
99
|
}
|
|
86
100
|
|
|
87
101
|
.expand-enter-from,
|
|
88
102
|
.expand-leave-to {
|
|
89
|
-
|
|
103
|
+
max-height: 0;
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
.expand-enter-to,
|
|
93
107
|
.expand-leave-from {
|
|
94
|
-
|
|
108
|
+
max-height: 300px;
|
|
95
109
|
}
|
|
96
110
|
</style>
|
package/src/components/Alert.vue
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="alert" :class="[type]" v-if="!isDismissed" :dismissable="dismissable" >
|
|
3
|
-
<Icon class="alert_icon" :icon="type" :size="2" :color="color[type]"/>
|
|
3
|
+
<Icon v-if="icon !== 'none'" class="alert_icon" :icon="icon || type" :size="2" :color="color[type]"/>
|
|
4
4
|
<p class="m-0">
|
|
5
5
|
{{ message }}
|
|
6
6
|
</p>
|
|
@@ -10,12 +10,14 @@
|
|
|
10
10
|
|
|
11
11
|
<script setup lang="ts">
|
|
12
12
|
import { Icon } from '@bagelink/vue';
|
|
13
|
+
import type { MaterialIcons } from '@bagelink/vue';
|
|
13
14
|
import Btn from './Btn.vue';
|
|
14
15
|
|
|
15
16
|
type Props = {
|
|
16
17
|
message: string;
|
|
17
18
|
dismissable?: boolean;
|
|
18
|
-
type
|
|
19
|
+
type?: 'info' | 'warning' | 'error';
|
|
20
|
+
icon?: MaterialIcons | 'none';
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
withDefaults(
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="avatar flex" :style="{ width: `${size}px`, height: `${size}px` }">
|
|
2
|
+
<div class="avatar flex justify-content-center" :style="{ width: `${size}px`, height: `${size}px` }">
|
|
3
3
|
<img v-if="src" :src="src" :alt="name">
|
|
4
4
|
<p v-else :style="{ 'line-height': `${size}px`, 'font-size': `calc(1.5rem * ${size} / 50)` }">
|
|
5
5
|
{{ fallback || initials(name || '') }}
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
</div>
|
|
17
17
|
<div class="Handlers">
|
|
18
18
|
<span @click="prev">
|
|
19
|
-
<slot name="prev" />
|
|
19
|
+
<slot :prev :index="activeSlideIndex" name="prev" />
|
|
20
20
|
</span>
|
|
21
21
|
<span @click="next">
|
|
22
|
-
<slot name="next" />
|
|
22
|
+
<slot :next :index="activeSlideIndex" name="next" />
|
|
23
23
|
</span>
|
|
24
24
|
</div>
|
|
25
25
|
</div>
|
package/src/components/Modal.vue
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<Title class="modal-title" tag="h3" v-if="title" :label="title" />
|
|
16
16
|
</header>
|
|
17
17
|
<slot />
|
|
18
|
-
<footer class="modal-footer mt-3">
|
|
18
|
+
<footer v-if="slots['footer'] || actions?.length" class="modal-footer mt-3">
|
|
19
19
|
<Btn
|
|
20
20
|
v-for="(action, i) in actions"
|
|
21
21
|
:key="i"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
</template>
|
|
30
30
|
|
|
31
31
|
<script lang="ts" setup>
|
|
32
|
-
import { onMounted, onUnmounted, watch } from 'vue';
|
|
32
|
+
import { onMounted, onUnmounted, watch, useSlots } from 'vue';
|
|
33
33
|
import { type BtnOptions, Btn, useEscape, Title, Card } from '@bagelink/vue';
|
|
34
34
|
import '../styles/modal.css';
|
|
35
35
|
|
|
@@ -42,6 +42,8 @@ const props = defineProps<{
|
|
|
42
42
|
visible?: boolean;
|
|
43
43
|
}>();
|
|
44
44
|
|
|
45
|
+
const slots = useSlots();
|
|
46
|
+
|
|
45
47
|
let isVisible = $ref<boolean>(false);
|
|
46
48
|
|
|
47
49
|
watch(
|
|
@@ -6,15 +6,18 @@
|
|
|
6
6
|
class="col"
|
|
7
7
|
v-for="field in computedSchema"
|
|
8
8
|
:key="field.id"
|
|
9
|
-
@click="sort(field?.id || '')"
|
|
9
|
+
@click="sort(field?.id || '')"
|
|
10
|
+
>
|
|
10
11
|
<div class="flex">
|
|
11
12
|
{{ field.label || keyToLabel(field.id) }}
|
|
12
13
|
<div
|
|
13
14
|
class="list-arrows"
|
|
14
|
-
:class="{ sorted: sortField === field.id }"
|
|
15
|
+
:class="{ sorted: sortField === field.id }"
|
|
16
|
+
>
|
|
15
17
|
<MaterialIcon
|
|
16
18
|
:class="{ desc: sortDirection === 'DESC' }"
|
|
17
|
-
icon="keyboard_arrow_up"
|
|
19
|
+
icon="keyboard_arrow_up"
|
|
20
|
+
/>
|
|
18
21
|
</div>
|
|
19
22
|
</div>
|
|
20
23
|
</th>
|
|
@@ -24,25 +27,29 @@
|
|
|
24
27
|
v-for="row in computedData"
|
|
25
28
|
:key="row.id"
|
|
26
29
|
@click="selectElement(row)"
|
|
27
|
-
class="row row-item position-relative"
|
|
30
|
+
class="row row-item position-relative"
|
|
31
|
+
>
|
|
28
32
|
<td
|
|
29
33
|
class="col"
|
|
30
34
|
v-for="field in computedSchema.map((c) => ({
|
|
31
35
|
...c,
|
|
32
36
|
transform: undefined,
|
|
33
37
|
}))"
|
|
34
|
-
:key="`${field.id}-${row.id}`"
|
|
38
|
+
:key="`${field.id}-${row.id}`"
|
|
39
|
+
>
|
|
35
40
|
<slot
|
|
36
41
|
v-if="field.id && slots[field.id]"
|
|
37
42
|
:name="field.id"
|
|
38
43
|
:row="row"
|
|
39
|
-
:field="field"
|
|
44
|
+
:field="field"
|
|
45
|
+
/>
|
|
40
46
|
<div v-else>
|
|
41
47
|
<BglField
|
|
42
48
|
class="embedded-field"
|
|
43
49
|
:field="field"
|
|
44
50
|
:modelValue="row"
|
|
45
|
-
label=""
|
|
51
|
+
label=""
|
|
52
|
+
/>
|
|
46
53
|
</div>
|
|
47
54
|
</td>
|
|
48
55
|
</tr>
|
|
@@ -65,14 +72,17 @@ const loading = $ref(true);
|
|
|
65
72
|
|
|
66
73
|
const props = defineProps<{
|
|
67
74
|
data: any[];
|
|
68
|
-
schema
|
|
75
|
+
schema?: BglFormSchemaT | (() => BglFormSchemaT);
|
|
69
76
|
}>();
|
|
70
77
|
|
|
71
78
|
const computedSchema = $computed(() => {
|
|
72
79
|
if (typeof props.schema === 'function') {
|
|
73
80
|
return props.schema();
|
|
74
81
|
}
|
|
75
|
-
return props.schema;
|
|
82
|
+
if (props.schema) return props.schema;
|
|
83
|
+
const keys = [...new Set((props.data || []).map(Object.keys).flat())] as string[];
|
|
84
|
+
const schema: BglFormSchemaT = keys.map((id) => ({ id, label: keyToLabel(id) }));
|
|
85
|
+
return schema;
|
|
76
86
|
});
|
|
77
87
|
|
|
78
88
|
const emit = defineEmits(['select', 'orderBy']);
|
|
@@ -5,11 +5,14 @@
|
|
|
5
5
|
inline
|
|
6
6
|
week-start="0"
|
|
7
7
|
v-model="selectedDate"
|
|
8
|
+
:allowed-dates="allowedDates"
|
|
9
|
+
:disabled-dates="disabledDates"
|
|
8
10
|
:auto-apply="true"
|
|
9
11
|
:highlight-week-days="[6]"
|
|
10
12
|
:enable-time-picker="false"
|
|
11
13
|
:month-change-on-scroll="false"
|
|
12
|
-
v-bind="options"
|
|
14
|
+
v-bind="options"
|
|
15
|
+
>
|
|
13
16
|
<template #action-buttons />
|
|
14
17
|
<template #action-preview />
|
|
15
18
|
</VDatepicker>
|
|
@@ -21,7 +24,8 @@
|
|
|
21
24
|
:id="`${hr}_${id}`"
|
|
22
25
|
:name="label"
|
|
23
26
|
:value="hr"
|
|
24
|
-
v-model="selectedHour"
|
|
27
|
+
v-model="selectedHour"
|
|
28
|
+
/>
|
|
25
29
|
<label :for="`${hr}_${id}`">{{ hr }}</label>
|
|
26
30
|
</template>
|
|
27
31
|
</div>
|
|
@@ -38,6 +42,8 @@ const props = defineProps<{
|
|
|
38
42
|
options?: Record<string, any>;
|
|
39
43
|
showTimeWrap?: boolean;
|
|
40
44
|
modelValue?: Date;
|
|
45
|
+
allowedDates?: string[] | Date[];
|
|
46
|
+
disabledDates?: string[] | Date[];
|
|
41
47
|
}>();
|
|
42
48
|
|
|
43
49
|
const emit = defineEmits(['update:modelValue']);
|
|
@@ -12,18 +12,14 @@
|
|
|
12
12
|
:class="{
|
|
13
13
|
fileDropZone: !storageFiles.length && !fileQueue.length,
|
|
14
14
|
dragover: isDragOver,
|
|
15
|
-
}"
|
|
15
|
+
}"
|
|
16
|
+
>
|
|
16
17
|
<template v-for="file in storageFiles" :key="file.id">
|
|
17
18
|
<div class="imagePreviewWrap" v-if="!multiple">
|
|
18
19
|
<img class="preview" :src="file.url" alt="" />
|
|
19
20
|
</div>
|
|
20
21
|
<div class="previewName">
|
|
21
|
-
<img
|
|
22
|
-
height="60"
|
|
23
|
-
v-if="multiple"
|
|
24
|
-
class="preview"
|
|
25
|
-
:src="file.url"
|
|
26
|
-
alt="" />
|
|
22
|
+
<img v-if="multiple" class="preview" :src="file.url" alt="" />
|
|
27
23
|
<p class="no-margin">
|
|
28
24
|
{{ file.name }}
|
|
29
25
|
</p>
|
|
@@ -32,7 +28,8 @@
|
|
|
32
28
|
@click.stop="removeFile(file)"
|
|
33
29
|
flat
|
|
34
30
|
icon="delete"
|
|
35
|
-
color="red"
|
|
31
|
+
color="red"
|
|
32
|
+
/>
|
|
36
33
|
</div>
|
|
37
34
|
</template>
|
|
38
35
|
<template v-for="fileQ in fileQueue" :key="fileQ.file">
|
|
@@ -41,11 +38,12 @@
|
|
|
41
38
|
</div>
|
|
42
39
|
<div class="previewName">
|
|
43
40
|
<img
|
|
44
|
-
|
|
41
|
+
:width="width || '220'"
|
|
45
42
|
v-if="multiple"
|
|
46
43
|
class="preview"
|
|
47
44
|
:src="fileToUrl(fileQ.file)"
|
|
48
|
-
alt=""
|
|
45
|
+
alt=""
|
|
46
|
+
/>
|
|
49
47
|
<p class="no-margin">
|
|
50
48
|
{{ fileQ.name }}
|
|
51
49
|
</p>
|
|
@@ -53,7 +51,8 @@
|
|
|
53
51
|
class="pie"
|
|
54
52
|
:style="`--p:${fileQ.progress}`"
|
|
55
53
|
style="--b: 2px"
|
|
56
|
-
:class="{ complete: fileQ.progress === 100 }"
|
|
54
|
+
:class="{ complete: fileQ.progress === 100 }"
|
|
55
|
+
>
|
|
57
56
|
<span class="progress" v-if="fileQ.progress < 100">
|
|
58
57
|
{{ `${fileQ.progress.toFixed(0)}` }}
|
|
59
58
|
</span>
|
|
@@ -66,7 +65,7 @@
|
|
|
66
65
|
</template>
|
|
67
66
|
|
|
68
67
|
<script setup lang="ts">
|
|
69
|
-
import { watch } from 'vue';
|
|
68
|
+
import { onMounted, watch } from 'vue';
|
|
70
69
|
import { Btn, type StorageFile, useBagel, MaterialIcon } from '@bagelink/vue';
|
|
71
70
|
|
|
72
71
|
const bagel = useBagel();
|
|
@@ -84,11 +83,12 @@ type StrKey = keyof StorageFile;
|
|
|
84
83
|
type FSValue = string[] | string | number;
|
|
85
84
|
|
|
86
85
|
const props = defineProps<{
|
|
87
|
-
label
|
|
86
|
+
label?: string;
|
|
88
87
|
multiple?: boolean;
|
|
89
88
|
files?: StorageFile | StorageFile[];
|
|
90
89
|
deleteEndpoint?: string;
|
|
91
90
|
bindkey?: StrKey;
|
|
91
|
+
width?: string;
|
|
92
92
|
}>();
|
|
93
93
|
|
|
94
94
|
const bindKey: StrKey = props.bindkey || 'id';
|
|
@@ -99,12 +99,36 @@ const storageFiles = $ref<StorageFile[]>([]);
|
|
|
99
99
|
const compareIds = (v1?: FSValue, v2?: FSValue) =>
|
|
100
100
|
[v1].flat().join(',') === [v2].flat().join(',');
|
|
101
101
|
|
|
102
|
+
onMounted(() => {
|
|
103
|
+
if (!props.files && [file_bindkeys.value].flat().length) {
|
|
104
|
+
const ids = [file_bindkeys.value].flat();
|
|
105
|
+
if (props.multiple) {
|
|
106
|
+
ids.forEach((id) => {
|
|
107
|
+
void bagel.get<StorageFile>(`/files/${id}`).then((file) => {
|
|
108
|
+
storageFiles.push(file);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
void bagel.get<StorageFile>(`/files/${ids[0]}`).then((file) => {
|
|
113
|
+
storageFiles.push(file);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
102
119
|
watch(
|
|
103
120
|
() => props.files,
|
|
104
121
|
(newFiles) => {
|
|
105
|
-
if (newFiles)
|
|
122
|
+
if (newFiles) {
|
|
123
|
+
const filesToAdd = [newFiles]
|
|
124
|
+
.flat()
|
|
125
|
+
.filter((f) => !storageFiles.find((sf) => sf[bindKey] === f[bindKey]));
|
|
126
|
+
for (const file of filesToAdd) {
|
|
127
|
+
storageFiles.push(file);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
106
130
|
},
|
|
107
|
-
{ immediate: true }
|
|
131
|
+
{ immediate: true },
|
|
108
132
|
);
|
|
109
133
|
|
|
110
134
|
watch(
|
|
@@ -119,7 +143,7 @@ watch(
|
|
|
119
143
|
file_bindkeys.value = idValue;
|
|
120
144
|
}
|
|
121
145
|
},
|
|
122
|
-
{ deep: true }
|
|
146
|
+
{ deep: true },
|
|
123
147
|
);
|
|
124
148
|
|
|
125
149
|
const fileQueue = $ref<QueueFile[]>([]);
|
|
@@ -159,7 +183,7 @@ const browse = () => {
|
|
|
159
183
|
const target = e?.target as HTMLInputElement;
|
|
160
184
|
if (target?.files) {
|
|
161
185
|
Array.from(target.files).forEach((file: File) =>
|
|
162
|
-
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
186
|
+
fileQueue.push({ name: file.name, file, progress: 0 }),
|
|
163
187
|
);
|
|
164
188
|
}
|
|
165
189
|
flushQueue();
|
|
@@ -183,7 +207,7 @@ const drop = (e: DragEvent) => {
|
|
|
183
207
|
preventDefault(e);
|
|
184
208
|
if (e.dataTransfer) {
|
|
185
209
|
Array.from(e.dataTransfer.files).forEach((file: File) =>
|
|
186
|
-
fileQueue.push({ name: file.name, file, progress: 0 })
|
|
210
|
+
fileQueue.push({ name: file.name, file, progress: 0 }),
|
|
187
211
|
);
|
|
188
212
|
}
|
|
189
213
|
isDragOver = false;
|
|
@@ -193,14 +217,18 @@ const drop = (e: DragEvent) => {
|
|
|
193
217
|
|
|
194
218
|
<style scoped>
|
|
195
219
|
.bagel-input .fileUploadWrap {
|
|
220
|
+
--width: 320px;
|
|
196
221
|
outline: 1px solid var(--border-color);
|
|
197
222
|
border-radius: var(--input-border-radius);
|
|
198
223
|
text-align: center;
|
|
199
224
|
cursor: pointer;
|
|
200
225
|
transition: var(--bgl-transition);
|
|
201
226
|
position: relative;
|
|
202
|
-
height: 132px;
|
|
227
|
+
min-height: 132px;
|
|
228
|
+
max-height: 500px;
|
|
203
229
|
font-size: var(--input-font-size);
|
|
230
|
+
overflow-y: auto;
|
|
231
|
+
background: var(--input-bg);
|
|
204
232
|
}
|
|
205
233
|
|
|
206
234
|
.previewName {
|
|
@@ -208,7 +236,8 @@ const drop = (e: DragEvent) => {
|
|
|
208
236
|
text-align: start;
|
|
209
237
|
color: var(--input-color);
|
|
210
238
|
display: grid;
|
|
211
|
-
grid-template-columns: 1fr 22px;
|
|
239
|
+
grid-template-columns: auto 1fr 22px;
|
|
240
|
+
gap: 1rem;
|
|
212
241
|
align-items: center;
|
|
213
242
|
padding-inline: 14px;
|
|
214
243
|
}
|
|
@@ -222,14 +251,16 @@ const drop = (e: DragEvent) => {
|
|
|
222
251
|
.imagePreviewWrap {
|
|
223
252
|
background: var(--input-bg);
|
|
224
253
|
border-radius: var(--input-border-radius);
|
|
225
|
-
height: 90px;
|
|
226
254
|
padding: 5px;
|
|
255
|
+
min-height: 90px;
|
|
227
256
|
}
|
|
228
257
|
|
|
229
258
|
img.preview {
|
|
230
|
-
|
|
259
|
+
width: var(--width);
|
|
260
|
+
/* max-width: calc(var(--width) * 2); */
|
|
231
261
|
border-radius: var(--input-border-radius);
|
|
232
|
-
object-fit:
|
|
262
|
+
object-fit: cover;
|
|
263
|
+
background: var(--bgl-white);
|
|
233
264
|
}
|
|
234
265
|
|
|
235
266
|
.fileUploadWrap.dragover,
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
:name="id"
|
|
12
12
|
:value="getValue(option)"
|
|
13
13
|
:checked="selectedValue === getValue(option)"
|
|
14
|
-
@change="handleSelect"
|
|
14
|
+
@change="handleSelect"
|
|
15
|
+
/>
|
|
15
16
|
<label :for="`${id}-${getValue(option)}`">{{ getLabel(option) }}</label>
|
|
16
17
|
</div>
|
|
17
18
|
</div>
|
|
@@ -50,9 +51,9 @@ const props = withDefaults(
|
|
|
50
51
|
}>(),
|
|
51
52
|
{
|
|
52
53
|
modelValue: '',
|
|
53
|
-
id: () => `radio-pill-${Math.random().toString(36).
|
|
54
|
+
id: () => `radio-pill-${Math.random().toString(36).substring(2, 9)}`,
|
|
54
55
|
label: '',
|
|
55
|
-
}
|
|
56
|
+
},
|
|
56
57
|
);
|
|
57
58
|
|
|
58
59
|
let selectedValue = $ref('');
|
|
@@ -68,7 +69,7 @@ watch(
|
|
|
68
69
|
if (newVal === oldVal || oldVal === undefined) return;
|
|
69
70
|
if (selectedValue !== newVal) selectedValue = newVal;
|
|
70
71
|
},
|
|
71
|
-
{ immediate: true }
|
|
72
|
+
{ immediate: true },
|
|
72
73
|
);
|
|
73
74
|
|
|
74
75
|
onMounted(() => {
|