sprintify-ui 0.0.10 → 0.0.12
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/sprintify-ui.es.js +5174 -6624
- package/dist/style.css +1 -1
- package/dist/tailwindcss/index.js +23 -0
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +0 -1
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +0 -1
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +13 -3
- package/dist/types/src/components/BaseCharacterCounter.vue.d.ts +143 -0
- package/dist/types/src/components/BaseDataTable.vue.d.ts +95 -64
- package/dist/types/src/components/BaseDialog.vue.d.ts +8 -8
- package/dist/types/src/components/BaseFilePicker.vue.d.ts +3 -3
- package/dist/types/src/components/BaseInput.vue.d.ts +39 -5
- package/dist/types/src/components/BaseLoadingCover.vue.d.ts +84 -12
- package/dist/types/src/components/BaseMenuItem.vue.d.ts +4 -4
- package/dist/types/src/components/BaseModalCenter.vue.d.ts +8 -8
- package/dist/types/src/components/BaseModalSide.vue.d.ts +8 -8
- package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +4 -4
- package/dist/types/src/components/BasePagination.vue.d.ts +105 -13
- package/dist/types/src/components/BasePaginationSimple.vue.d.ts +2 -2
- package/dist/types/src/components/BaseSelect.vue.d.ts +130 -26
- package/dist/types/src/components/BaseSwitch.vue.d.ts +15 -8
- package/dist/types/src/components/BaseTabItem.vue.d.ts +26 -4
- package/dist/types/src/components/BaseTableColumn.vue.d.ts +4 -4
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +175 -21
- package/dist/types/src/components/index.d.ts +24 -1
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/svg/BaseEmptyState.vue.d.ts +2 -0
- package/dist/types/src/{components/BaseSpinner.vue.d.ts → svg/BaseSpinnerLarge.vue.d.ts} +0 -0
- package/dist/types/src/svg/BaseSpinnerSmall.vue.d.ts +44 -0
- package/dist/types/src/types/types.d.ts +1 -1
- package/package.json +4 -2
- package/src/components/BaseAutocomplete.stories.js +7 -4
- package/src/components/BaseAutocomplete.vue +44 -15
- package/src/components/BaseAutocompleteFetch.stories.js +6 -3
- package/src/components/BaseAutocompleteFetch.vue +8 -3
- package/src/components/BaseBelongsTo.stories.js +9 -4
- package/src/components/BaseBelongsTo.vue +1 -0
- package/src/components/BaseCard.vue +1 -1
- package/src/components/BaseCharacterCounter.stories.js +30 -0
- package/src/components/BaseCharacterCounter.vue +60 -0
- package/src/components/BaseDataIterator.stories.js +102 -3
- package/src/components/BaseDataIterator.vue +75 -49
- package/src/components/BaseDataTable.stories.js +149 -2
- package/src/components/BaseDataTable.vue +34 -28
- package/src/components/BaseDataTableToggleColumns.vue +1 -1
- package/src/components/BaseDateSelect.vue +6 -2
- package/src/components/BaseDescriptionListItem.vue +40 -4
- package/src/components/BaseDialog.stories.js +51 -0
- package/src/components/BaseDialog.vue +13 -7
- package/src/components/BaseFilePicker.stories.js +51 -0
- package/src/components/BaseFilePicker.vue +6 -6
- package/src/components/BaseFileUploader.stories.js +80 -0
- package/src/components/BaseFileUploader.vue +16 -3
- package/src/components/BaseInput.stories.js +46 -0
- package/src/components/BaseInput.vue +10 -2
- package/src/components/BaseInputLabel.stories.js +31 -0
- package/src/components/BaseInputLabel.vue +1 -1
- package/src/components/BaseLoadingCover.stories.js +55 -0
- package/src/components/BaseLoadingCover.vue +27 -17
- package/src/components/BaseMenu.stories.js +125 -0
- package/src/components/BaseModalCenter.stories.js +61 -0
- package/src/components/BaseModalCenter.vue +2 -2
- package/src/components/BaseModalSide.stories.js +55 -0
- package/src/components/BaseModalSide.vue +2 -2
- package/src/components/BaseNavbar.stories.js +150 -0
- package/src/components/BaseNavbar.vue +3 -0
- package/src/components/BaseNavbarItem.vue +1 -0
- package/src/components/BaseNavbarItemContent.vue +3 -0
- package/src/components/BasePagination.stories.js +32 -0
- package/src/components/BasePagination.vue +126 -40
- package/src/components/BasePaginationSimple.vue +3 -3
- package/src/components/BasePanel.stories.js +56 -0
- package/src/components/BasePassword.stories.js +36 -0
- package/src/components/BasePassword.vue +11 -5
- package/src/components/BaseProcessRing.stories.js +27 -0
- package/src/components/BaseReadMore.stories.js +30 -0
- package/src/components/BaseReadMore.vue +1 -1
- package/src/components/BaseSelect.stories.js +67 -0
- package/src/components/BaseSelect.vue +144 -44
- package/src/components/BaseSideNavigation.stories.js +55 -0
- package/src/components/BaseSideNavigation.vue +7 -2
- package/src/components/BaseSideNavigationItem.vue +11 -3
- package/src/components/BaseSkeleton.stories.js +36 -0
- package/src/components/BaseSwitch.stories.js +101 -0
- package/src/components/BaseSwitch.vue +90 -12
- package/src/components/BaseSystemAlert.stories.js +63 -0
- package/src/components/BaseTabItem.vue +19 -6
- package/src/components/BaseTable.vue +42 -29
- package/src/components/BaseTableColumn.vue +2 -2
- package/src/components/BaseTabs.stories.js +54 -0
- package/src/components/BaseTabs.vue +3 -3
- package/src/components/BaseTextarea.stories.js +35 -0
- package/src/components/BaseTextarea.vue +1 -1
- package/src/components/BaseTextareaAutoresize.stories.js +49 -0
- package/src/components/BaseTextareaAutoresize.vue +83 -87
- package/src/components/index.ts +46 -0
- package/src/lang/en.json +1 -0
- package/src/lang/fr.json +1 -0
- package/src/svg/BaseEmptyState.vue +34 -0
- package/src/{components/BaseSpinner.vue → svg/BaseSpinnerLarge.vue} +0 -0
- package/src/svg/BaseSpinnerSmall.vue +9 -0
- package/src/types/types.ts +1 -1
- package/dist/types/src/components/BaseWordCount.vue.d.ts +0 -31
- package/src/components/BaseWordCount.vue +0 -36
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
firstLoad,
|
|
21
21
|
}"
|
|
22
22
|
>
|
|
23
|
-
<BaseCard clipped class="
|
|
23
|
+
<BaseCard clipped class="w-full overflow-hidden">
|
|
24
24
|
<BaseTable
|
|
25
25
|
ref="table"
|
|
26
26
|
:data="items"
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
<BaseTableColumn
|
|
49
49
|
v-slot="{ row }"
|
|
50
50
|
:visible="editButton || deleteButton || $slots.rowActions != null"
|
|
51
|
-
:
|
|
51
|
+
:toggle="false"
|
|
52
52
|
>
|
|
53
53
|
<div class="flex justify-end text-right">
|
|
54
54
|
<slot name="rowActions" :row="row" />
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
:to="editUrl(row)"
|
|
59
59
|
:disabled="!canUpdate(row)"
|
|
60
60
|
>
|
|
61
|
-
<button class="btn btn-white p-2">
|
|
61
|
+
<button class="btn btn-white bg-transparent p-2">
|
|
62
62
|
<BaseIcon
|
|
63
63
|
icon="heroicons:cog-6-tooth-solid"
|
|
64
64
|
class="text-slate-500"
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
<button
|
|
70
70
|
v-if="deleteButton && deleteUrl"
|
|
71
71
|
type="button"
|
|
72
|
-
class="btn btn-white p-2"
|
|
72
|
+
class="btn btn-white bg-transparent p-2"
|
|
73
73
|
:disabled="!canDelete(row)"
|
|
74
74
|
@click="onDeleteClick(row)"
|
|
75
75
|
>
|
|
@@ -107,11 +107,8 @@
|
|
|
107
107
|
class="flex items-center justify-center py-16"
|
|
108
108
|
>
|
|
109
109
|
<div class="flex flex-col items-center">
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
alt="No data"
|
|
113
|
-
width="100"
|
|
114
|
-
/>
|
|
110
|
+
<BaseEmptyState class="w-32"></BaseEmptyState>
|
|
111
|
+
|
|
115
112
|
<p class="mt-3 text-center text-sm text-slate-600">
|
|
116
113
|
{{ $t('sui.nothing_found') }}
|
|
117
114
|
</p>
|
|
@@ -138,7 +135,7 @@
|
|
|
138
135
|
<slot name="sidebarTop" v-bind="sidebarProps"></slot>
|
|
139
136
|
</template>
|
|
140
137
|
|
|
141
|
-
<template #sidebarBottom>
|
|
138
|
+
<template v-if="toggleable" #sidebarBottom>
|
|
142
139
|
<div class="mb-3">
|
|
143
140
|
<h3
|
|
144
141
|
class="mb-1 text-xs font-semibold uppercase tracking-wider text-slate-500"
|
|
@@ -177,6 +174,7 @@ import BaseTable from './BaseTable.vue';
|
|
|
177
174
|
import BaseTableColumn from './BaseTableColumn.vue';
|
|
178
175
|
import BaseDataTableToggleColumns from './BaseDataTableToggleColumns.vue';
|
|
179
176
|
import { config } from '@/index';
|
|
177
|
+
import BaseEmptyState from '../svg/BaseEmptyState.vue';
|
|
180
178
|
|
|
181
179
|
const i18n = useI18n();
|
|
182
180
|
|
|
@@ -196,22 +194,6 @@ const props = defineProps({
|
|
|
196
194
|
type: String,
|
|
197
195
|
},
|
|
198
196
|
|
|
199
|
-
/**
|
|
200
|
-
* Show/Hide edit button
|
|
201
|
-
*/
|
|
202
|
-
editButton: {
|
|
203
|
-
default: true,
|
|
204
|
-
type: Boolean,
|
|
205
|
-
},
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Show/Hide delete button
|
|
209
|
-
*/
|
|
210
|
-
deleteButton: {
|
|
211
|
-
default: true,
|
|
212
|
-
type: Boolean,
|
|
213
|
-
},
|
|
214
|
-
|
|
215
197
|
/**
|
|
216
198
|
* Route key name for Laravel route model binding
|
|
217
199
|
*/
|
|
@@ -237,6 +219,14 @@ const props = defineProps({
|
|
|
237
219
|
type: Object as PropType<DataTableQuery>,
|
|
238
220
|
},
|
|
239
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Show/Hide edit button
|
|
224
|
+
*/
|
|
225
|
+
editButton: {
|
|
226
|
+
default: true,
|
|
227
|
+
type: Boolean,
|
|
228
|
+
},
|
|
229
|
+
|
|
240
230
|
/**
|
|
241
231
|
* Edit url for router link
|
|
242
232
|
*/
|
|
@@ -245,6 +235,14 @@ const props = defineProps({
|
|
|
245
235
|
type: Function as PropType<(row: CollectionItem) => string>,
|
|
246
236
|
},
|
|
247
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Show/Hide delete button
|
|
240
|
+
*/
|
|
241
|
+
deleteButton: {
|
|
242
|
+
default: true,
|
|
243
|
+
type: Boolean,
|
|
244
|
+
},
|
|
245
|
+
|
|
248
246
|
/**
|
|
249
247
|
* Delete endpoint to delete an item
|
|
250
248
|
*/
|
|
@@ -262,7 +260,7 @@ const props = defineProps({
|
|
|
262
260
|
},
|
|
263
261
|
|
|
264
262
|
/**
|
|
265
|
-
*
|
|
263
|
+
* Check is a given row has details
|
|
266
264
|
*/
|
|
267
265
|
hasDetailedVisible: {
|
|
268
266
|
default() {
|
|
@@ -315,6 +313,14 @@ const props = defineProps({
|
|
|
315
313
|
type: Boolean,
|
|
316
314
|
},
|
|
317
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Shows the column toggle utility
|
|
318
|
+
*/
|
|
319
|
+
toggleable: {
|
|
320
|
+
default: true,
|
|
321
|
+
type: Boolean,
|
|
322
|
+
},
|
|
323
|
+
|
|
318
324
|
/**
|
|
319
325
|
* Actions
|
|
320
326
|
*/
|
|
@@ -388,7 +394,7 @@ function onDeleteClick(row: CollectionItem) {
|
|
|
388
394
|
title: i18n.t('sui.delete_record') + '?',
|
|
389
395
|
message: i18n.t('sui.delete_record_description'),
|
|
390
396
|
color: 'danger',
|
|
391
|
-
closeOnOutsideClick:
|
|
397
|
+
closeOnOutsideClick: true,
|
|
392
398
|
confirmText: i18n.t('sui.yes_delete'),
|
|
393
399
|
onConfirm: () => onDelete(row),
|
|
394
400
|
});
|
|
@@ -54,13 +54,13 @@
|
|
|
54
54
|
<div class="w-auto p-0.5">
|
|
55
55
|
<select
|
|
56
56
|
v-model="date.day"
|
|
57
|
-
:disabled="
|
|
57
|
+
:disabled="dayDisabled"
|
|
58
58
|
:required="required"
|
|
59
59
|
data-cy="day"
|
|
60
60
|
class="w-full rounded capitalize"
|
|
61
61
|
:class="[
|
|
62
62
|
{
|
|
63
|
-
'cursor-not-allowed bg-slate-100 text-slate-500':
|
|
63
|
+
'cursor-not-allowed bg-slate-100 text-slate-500': dayDisabled,
|
|
64
64
|
},
|
|
65
65
|
inputClass,
|
|
66
66
|
]"
|
|
@@ -189,4 +189,8 @@ function getDateTime(): DateTime | null {
|
|
|
189
189
|
padStart(date.value.day + '', 2, '0')
|
|
190
190
|
);
|
|
191
191
|
}
|
|
192
|
+
|
|
193
|
+
const dayDisabled = computed(() => {
|
|
194
|
+
return days.value.length == 0 || props.disabled;
|
|
195
|
+
});
|
|
192
196
|
</script>
|
|
@@ -1,12 +1,48 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
|
|
2
|
+
<div
|
|
3
|
+
ref="item"
|
|
4
|
+
:class="{
|
|
5
|
+
'px-4 py-4': mobile,
|
|
6
|
+
'grid grid-cols-3 gap-4 py-5 px-6': !mobile,
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
<dt class="text-sm font-medium leading-tight text-slate-500">
|
|
4
10
|
<slot name="left" />
|
|
5
11
|
</dt>
|
|
6
|
-
<dd
|
|
12
|
+
<dd
|
|
13
|
+
class="text-sm leading-tight text-slate-900"
|
|
14
|
+
:class="{
|
|
15
|
+
'mt-1.5': mobile,
|
|
16
|
+
'col-span-2': !mobile,
|
|
17
|
+
}"
|
|
18
|
+
>
|
|
7
19
|
<slot name="right" />
|
|
8
20
|
</dd>
|
|
9
21
|
</div>
|
|
10
22
|
</template>
|
|
11
23
|
|
|
12
|
-
<script lang="ts" setup
|
|
24
|
+
<script lang="ts" setup>
|
|
25
|
+
import { useResizeObserver } from '@vueuse/core';
|
|
26
|
+
import { debounce } from 'lodash';
|
|
27
|
+
import { Ref } from 'vue';
|
|
28
|
+
import breakpoints from '../../config/breakpoints.json';
|
|
29
|
+
|
|
30
|
+
const DEFAULT_WIDTH = 800;
|
|
31
|
+
|
|
32
|
+
const item = ref(null) as Ref<HTMLElement | null>;
|
|
33
|
+
const width = ref(DEFAULT_WIDTH);
|
|
34
|
+
|
|
35
|
+
const mobile = computed(() => {
|
|
36
|
+
return width.value < breakpoints.sm;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
function setWidth() {
|
|
40
|
+
width.value = item.value?.clientWidth ?? DEFAULT_WIDTH;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
onMounted(() => {
|
|
44
|
+
setWidth();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
useResizeObserver(item, debounce(setWidth, 50));
|
|
48
|
+
</script>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import BaseDialog from './BaseDialog.vue';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Components/BaseDialog',
|
|
5
|
+
component: BaseDialog,
|
|
6
|
+
argTypes: {
|
|
7
|
+
color: {
|
|
8
|
+
control: { type: 'select' },
|
|
9
|
+
options: ['success', 'info', 'warning', 'danger'],
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
args: {
|
|
13
|
+
message:
|
|
14
|
+
'Nisi Lorem sunt amet aliqua dolor ullamco deserunt enim irure non ad. Excepteur culpa consectetur dolore culpa sunt aliquip proident quis.',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const Template = (args) => ({
|
|
19
|
+
components: { BaseDialog },
|
|
20
|
+
setup() {
|
|
21
|
+
return { args };
|
|
22
|
+
},
|
|
23
|
+
template: `
|
|
24
|
+
<BaseDialog v-bind="args">
|
|
25
|
+
</BaseDialog>
|
|
26
|
+
`,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const Demo = Template.bind({});
|
|
30
|
+
Demo.args = {
|
|
31
|
+
title: 'Be careful',
|
|
32
|
+
color: 'warning',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const Success = Template.bind({});
|
|
36
|
+
Success.args = {
|
|
37
|
+
title: 'Success',
|
|
38
|
+
color: 'success',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Danger = Template.bind({});
|
|
42
|
+
Danger.args = {
|
|
43
|
+
title: 'Error',
|
|
44
|
+
color: 'danger',
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const Info = Template.bind({});
|
|
48
|
+
Info.args = {
|
|
49
|
+
title: 'Information',
|
|
50
|
+
color: 'info',
|
|
51
|
+
};
|
|
@@ -15,22 +15,22 @@
|
|
|
15
15
|
<BaseIcon
|
|
16
16
|
v-if="color == 'danger'"
|
|
17
17
|
class="h-6 w-6 text-red-600"
|
|
18
|
-
icon="heroicons:
|
|
18
|
+
icon="heroicons:exclamation-triangle-20-solid"
|
|
19
19
|
/>
|
|
20
20
|
<BaseIcon
|
|
21
21
|
v-else-if="color == 'warning'"
|
|
22
22
|
class="h-6 w-6 text-yellow-600"
|
|
23
|
-
icon="heroicons:
|
|
23
|
+
icon="heroicons:exclamation-triangle-20-solid"
|
|
24
24
|
/>
|
|
25
25
|
<BaseIcon
|
|
26
26
|
v-else-if="color == 'success'"
|
|
27
27
|
class="h-6 w-6 text-green-600"
|
|
28
|
-
icon="heroicons:check-circle"
|
|
28
|
+
icon="heroicons:check-circle-20-solid"
|
|
29
29
|
/>
|
|
30
30
|
<BaseIcon
|
|
31
31
|
v-else
|
|
32
32
|
class="h-6 w-6 text-primary-600"
|
|
33
|
-
icon="heroicons:information-circle"
|
|
33
|
+
icon="heroicons:information-circle-20-solid"
|
|
34
34
|
/>
|
|
35
35
|
</div>
|
|
36
36
|
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
{{ title }}
|
|
43
43
|
</h3>
|
|
44
44
|
<div class="mt-2">
|
|
45
|
-
<p class="text-
|
|
45
|
+
<p class="text-base font-light text-slate-600">
|
|
46
46
|
{{ message }}
|
|
47
47
|
</p>
|
|
48
48
|
</div>
|
|
@@ -92,11 +92,17 @@ defineProps({
|
|
|
92
92
|
type: String,
|
|
93
93
|
},
|
|
94
94
|
confirmText: {
|
|
95
|
-
default
|
|
95
|
+
default() {
|
|
96
|
+
const i18n = useI18n();
|
|
97
|
+
return i18n.t('sui.confirm');
|
|
98
|
+
},
|
|
96
99
|
type: String,
|
|
97
100
|
},
|
|
98
101
|
cancelText: {
|
|
99
|
-
default
|
|
102
|
+
default() {
|
|
103
|
+
const i18n = useI18n();
|
|
104
|
+
return i18n.t('sui.cancel');
|
|
105
|
+
},
|
|
100
106
|
type: String,
|
|
101
107
|
},
|
|
102
108
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import BaseFilePicker from './BaseFilePicker.vue';
|
|
2
|
+
import { Icon as BaseIcon } from '@iconify/vue';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'Form/BaseFilePicker',
|
|
6
|
+
component: BaseFilePicker,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const Template = (args) => ({
|
|
10
|
+
components: { BaseFilePicker, BaseIcon },
|
|
11
|
+
setup() {
|
|
12
|
+
return { args };
|
|
13
|
+
},
|
|
14
|
+
template: `
|
|
15
|
+
<BaseFilePicker v-bind="args">
|
|
16
|
+
<template #default="{ dragging, disabled }">
|
|
17
|
+
<div
|
|
18
|
+
class="flex w-full items-center space-x-4 rounded-lg border-2 border-dashed border-slate-200 p-5 duration-100"
|
|
19
|
+
:class="[
|
|
20
|
+
dragging ? 'bg-slate-100' : 'bg-white',
|
|
21
|
+
disabled ? 'bg-slate-100 cursor-not-allowed' : 'hover:bg-slate-50',
|
|
22
|
+
]"
|
|
23
|
+
>
|
|
24
|
+
<div class="rounded-full bg-slate-200 p-2">
|
|
25
|
+
<BaseIcon
|
|
26
|
+
icon="heroicons:arrow-up-on-square"
|
|
27
|
+
class="h-6 w-6"
|
|
28
|
+
:class="[disabled ? 'text-slate-400' : 'text-slate-500']"
|
|
29
|
+
/>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="text-left">
|
|
32
|
+
<p
|
|
33
|
+
class="mb-0 text-sm font-medium leading-tight"
|
|
34
|
+
:class="[disabled ? 'text-slate-400' : 'text-slate-900']"
|
|
35
|
+
>
|
|
36
|
+
{{ $t("sui.drop_or_click_to_upload") }}
|
|
37
|
+
</p>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
</BaseFilePicker>
|
|
42
|
+
`,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const Demo = Template.bind({});
|
|
46
|
+
Demo.args = {};
|
|
47
|
+
|
|
48
|
+
export const Disabled = Template.bind({});
|
|
49
|
+
Disabled.args = {
|
|
50
|
+
disabled: true,
|
|
51
|
+
};
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
@dragenter.prevent="dragging = true"
|
|
13
13
|
@click="pickFile"
|
|
14
14
|
>
|
|
15
|
-
<slot :selecting="selecting" :dragging="dragging" />
|
|
15
|
+
<slot :selecting="selecting" :dragging="dragging" :disabled="disabled" />
|
|
16
16
|
</button>
|
|
17
17
|
<input
|
|
18
18
|
ref="input"
|
|
@@ -41,7 +41,7 @@ export default defineComponent({
|
|
|
41
41
|
type: String,
|
|
42
42
|
},
|
|
43
43
|
},
|
|
44
|
-
emits: ['
|
|
44
|
+
emits: ['select'],
|
|
45
45
|
data() {
|
|
46
46
|
return {
|
|
47
47
|
selecting: false,
|
|
@@ -63,7 +63,7 @@ export default defineComponent({
|
|
|
63
63
|
},
|
|
64
64
|
onInputChange() {
|
|
65
65
|
const files = (this.inputElement?.files ?? []) as File[];
|
|
66
|
-
this.
|
|
66
|
+
this.select(files);
|
|
67
67
|
},
|
|
68
68
|
handleDrop(e: any) {
|
|
69
69
|
if (this.disabled) {
|
|
@@ -72,9 +72,9 @@ export default defineComponent({
|
|
|
72
72
|
|
|
73
73
|
const files = e?.dataTransfer?.files ?? [];
|
|
74
74
|
|
|
75
|
-
this.
|
|
75
|
+
this.select(files);
|
|
76
76
|
},
|
|
77
|
-
async
|
|
77
|
+
async select(files: File[]) {
|
|
78
78
|
if (this.disabled) {
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
@@ -88,7 +88,7 @@ export default defineComponent({
|
|
|
88
88
|
try {
|
|
89
89
|
const file = files[0];
|
|
90
90
|
|
|
91
|
-
this.$emit('
|
|
91
|
+
this.$emit('select', file);
|
|
92
92
|
} finally {
|
|
93
93
|
if (this.inputElement) {
|
|
94
94
|
this.inputElement.value = '';
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import BaseFileUploader from './BaseFileUploader.vue';
|
|
2
|
+
import BaseLoadingCover from './BaseLoadingCover.vue';
|
|
3
|
+
import BaseAppNotifications from './BaseAppNotifications.vue';
|
|
4
|
+
import { Icon as BaseIcon } from '@iconify/vue';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Form/BaseFileUploader',
|
|
8
|
+
component: BaseFileUploader,
|
|
9
|
+
args: {
|
|
10
|
+
buttonClass: 'w-full',
|
|
11
|
+
acceptedExtensions: ['jpg', 'png'],
|
|
12
|
+
maxSize: 1024 * 200, // 200kb
|
|
13
|
+
url: 'https://dummyjson.com/posts/add',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const Template = (args) => ({
|
|
18
|
+
components: {
|
|
19
|
+
BaseFileUploader,
|
|
20
|
+
BaseIcon,
|
|
21
|
+
BaseLoadingCover,
|
|
22
|
+
BaseAppNotifications,
|
|
23
|
+
},
|
|
24
|
+
setup() {
|
|
25
|
+
return { args };
|
|
26
|
+
},
|
|
27
|
+
template: `
|
|
28
|
+
<BaseFileUploader v-bind="args">
|
|
29
|
+
<template #default="{ dragging, disabled, uploading, selecting }">
|
|
30
|
+
<div
|
|
31
|
+
class="flex w-full items-center space-x-4 rounded-lg border-2 border-dashed border-slate-200 p-5 duration-100"
|
|
32
|
+
:class="[
|
|
33
|
+
dragging ? 'bg-slate-100' : 'bg-white',
|
|
34
|
+
disabled ? 'bg-slate-100 cursor-not-allowed' : 'hover:bg-slate-50',
|
|
35
|
+
]"
|
|
36
|
+
>
|
|
37
|
+
<div class="rounded-full bg-slate-200 p-2">
|
|
38
|
+
<BaseIcon
|
|
39
|
+
icon="heroicons:arrow-up-on-square"
|
|
40
|
+
class="h-6 w-6"
|
|
41
|
+
:class="[disabled ? 'text-slate-400' : 'text-slate-500']"
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="text-left">
|
|
45
|
+
<p
|
|
46
|
+
class="mb-0 text-sm font-medium leading-tight"
|
|
47
|
+
:class="[disabled ? 'text-slate-400' : 'text-slate-900']"
|
|
48
|
+
>
|
|
49
|
+
{{ $t("sui.drop_or_click_to_upload") }}
|
|
50
|
+
</p>
|
|
51
|
+
<p class="text-sm text-slate-500 mt-1">Max 200kb</p>
|
|
52
|
+
<p class="text-sm text-slate-500">.jpg, .png</p>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
<template #loading="{ dragging, disabled, uploading, selecting }">
|
|
57
|
+
<BaseLoadingCover
|
|
58
|
+
:model-value="args.loading || uploading || selecting"
|
|
59
|
+
:delay="0"
|
|
60
|
+
icon-class="text-primary-600 w-6 h-6"
|
|
61
|
+
backdrop-class="bg-white opacity-60"
|
|
62
|
+
/>
|
|
63
|
+
</template>
|
|
64
|
+
</BaseFileUploader>
|
|
65
|
+
<BaseAppNotifications></BaseAppNotifications>
|
|
66
|
+
`,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export const Demo = Template.bind({});
|
|
70
|
+
Demo.args = {};
|
|
71
|
+
|
|
72
|
+
export const Disabled = Template.bind({});
|
|
73
|
+
Disabled.args = {
|
|
74
|
+
disabled: true,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const Loading = Template.bind({});
|
|
78
|
+
Loading.args = {
|
|
79
|
+
loading: true,
|
|
80
|
+
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
:button-class="buttonClass"
|
|
5
5
|
:disabled="uploading || disabled"
|
|
6
6
|
:accept="accept"
|
|
7
|
-
@
|
|
7
|
+
@select="onFileSelect"
|
|
8
8
|
>
|
|
9
9
|
<template #default="slotProps">
|
|
10
10
|
<slot
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
:disabled="slotProps.disabled"
|
|
23
23
|
>
|
|
24
24
|
<BaseLoadingCover
|
|
25
|
+
:delay="0"
|
|
25
26
|
icon-class="text-primary-600 w-6 h-6"
|
|
26
27
|
:model-value="loading || uploading || slotProps.selecting"
|
|
27
28
|
/>
|
|
@@ -37,6 +38,8 @@ import { PropType } from 'vue';
|
|
|
37
38
|
import { UploadedFile } from '@/types/UploadedFile';
|
|
38
39
|
import { toHumanList, fileSizeFormat } from '../utils';
|
|
39
40
|
import { useNotificationsStore } from '../stores/notifications';
|
|
41
|
+
import BaseLoadingCover from './BaseLoadingCover.vue';
|
|
42
|
+
import BaseFilePicker from './BaseFilePicker.vue';
|
|
40
43
|
|
|
41
44
|
const http = config.http;
|
|
42
45
|
const i18n = useI18n();
|
|
@@ -88,8 +91,15 @@ const emit = defineEmits([
|
|
|
88
91
|
|
|
89
92
|
const uploading = ref(false);
|
|
90
93
|
|
|
91
|
-
async function
|
|
94
|
+
async function onFileSelect(file: File) {
|
|
95
|
+
if (uploading.value) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
uploading.value = true;
|
|
100
|
+
|
|
92
101
|
if (!(await props.beforeUpload())) {
|
|
102
|
+
uploading.value = false;
|
|
93
103
|
return;
|
|
94
104
|
}
|
|
95
105
|
|
|
@@ -102,6 +112,8 @@ async function onPictureUpload(file: File) {
|
|
|
102
112
|
x: fileSizeFormat(props.maxSize),
|
|
103
113
|
}),
|
|
104
114
|
});
|
|
115
|
+
|
|
116
|
+
uploading.value = false;
|
|
105
117
|
return;
|
|
106
118
|
}
|
|
107
119
|
|
|
@@ -124,6 +136,8 @@ async function onPictureUpload(file: File) {
|
|
|
124
136
|
toHumanList(props.acceptedExtensions, i18n.t('sui.or')) +
|
|
125
137
|
'.',
|
|
126
138
|
});
|
|
139
|
+
|
|
140
|
+
uploading.value = false;
|
|
127
141
|
return;
|
|
128
142
|
}
|
|
129
143
|
}
|
|
@@ -132,7 +146,6 @@ async function onPictureUpload(file: File) {
|
|
|
132
146
|
|
|
133
147
|
formData.append('file', file);
|
|
134
148
|
|
|
135
|
-
uploading.value = true;
|
|
136
149
|
emit('upload:start');
|
|
137
150
|
|
|
138
151
|
const response = await http.post(props.url ?? config.upload_url, formData);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import BaseInput from './BaseInput.vue';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'Form/BaseInput',
|
|
5
|
+
component: BaseInput,
|
|
6
|
+
args: {
|
|
7
|
+
required: true,
|
|
8
|
+
type: 'text',
|
|
9
|
+
name: 'name',
|
|
10
|
+
class: 'w-full',
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const Template = (args) => ({
|
|
15
|
+
components: {
|
|
16
|
+
BaseInput,
|
|
17
|
+
},
|
|
18
|
+
setup() {
|
|
19
|
+
const value = ref('');
|
|
20
|
+
return { args, value };
|
|
21
|
+
},
|
|
22
|
+
template: `
|
|
23
|
+
<form @submit.prevent="" class="border-none">
|
|
24
|
+
<BaseInput v-model="value" v-bind="args"></BaseInput>
|
|
25
|
+
</form>
|
|
26
|
+
`,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const Demo = Template.bind({});
|
|
30
|
+
Demo.args = {
|
|
31
|
+
placeholder: 'Enter your name',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Number = Template.bind({});
|
|
35
|
+
Number.args = {
|
|
36
|
+
type: 'number',
|
|
37
|
+
step: 0.1,
|
|
38
|
+
placeholder: 'Enter a number',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const Disabled = Template.bind({});
|
|
42
|
+
Disabled.args = {
|
|
43
|
+
modelValue: 'Disabled input!',
|
|
44
|
+
disabled: true,
|
|
45
|
+
placeholder: 'Enter your name',
|
|
46
|
+
};
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
:value="modelValue"
|
|
5
5
|
:type="type"
|
|
6
6
|
:name="name"
|
|
7
|
+
:step="step"
|
|
7
8
|
:disabled="disabled"
|
|
8
9
|
:placeholder="placeholder"
|
|
9
10
|
:required="required"
|
|
10
|
-
class="rounded"
|
|
11
|
+
class="rounded border-slate-300 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
11
12
|
:autocomplete="autocomplete ? 'on' : 'off'"
|
|
12
13
|
@keydown.enter="onEnter"
|
|
13
14
|
@input="$emit('update:modelValue', transformInputValue($event))"
|
|
@@ -20,17 +21,24 @@ import { PropType } from 'vue';
|
|
|
20
21
|
|
|
21
22
|
const props = defineProps({
|
|
22
23
|
modelValue: {
|
|
23
|
-
|
|
24
|
+
default: '',
|
|
24
25
|
type: [String, Number, null] as PropType<string | number | null>,
|
|
25
26
|
},
|
|
26
27
|
type: {
|
|
27
28
|
type: String,
|
|
28
29
|
default: 'text',
|
|
29
30
|
},
|
|
31
|
+
step: {
|
|
32
|
+
default: undefined,
|
|
33
|
+
type: Number,
|
|
34
|
+
},
|
|
30
35
|
autocomplete: {
|
|
31
36
|
default: true,
|
|
32
37
|
type: Boolean,
|
|
33
38
|
},
|
|
39
|
+
/**
|
|
40
|
+
* Prevents submit when pressing 'Enter' while the input is focused.
|
|
41
|
+
*/
|
|
34
42
|
preventSubmit: {
|
|
35
43
|
default: false,
|
|
36
44
|
type: Boolean,
|