sprintify-ui 0.0.6 → 0.0.8
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/README.md +13 -0
- package/dist/sprintify-ui.es.js +9166 -8089
- package/dist/types/src/components/BaseApp.vue.d.ts +48 -0
- package/dist/types/src/components/BaseAppDialogs.vue.d.ts +80 -0
- package/dist/types/src/components/BaseAppNotifications.vue.d.ts +44 -0
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +7 -7
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +7 -7
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +4 -4
- package/dist/types/src/components/BaseDataIterator.vue.d.ts +4 -4
- package/dist/types/src/components/BaseDataTable.vue.d.ts +4 -4
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +20 -1
- package/dist/types/src/components/BaseInput.vue.d.ts +4 -4
- package/dist/types/src/components/BaseLoadingCover.vue.d.ts +4 -4
- package/dist/types/src/components/BasePassword.vue.d.ts +1 -1
- package/dist/types/src/components/BaseSelect.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTextarea.vue.d.ts +4 -4
- package/dist/types/src/components/BaseTextareaAutoresize.vue.d.ts +1 -1
- package/dist/types/src/components/index.d.ts +9 -1
- package/dist/types/src/index.d.ts +42 -32
- package/dist/types/src/stores/dialogs.d.ts +9 -0
- package/dist/types/src/stores/notifications.d.ts +10 -0
- package/dist/types/src/stores/systemAlerts.d.ts +9 -0
- package/dist/types/src/types/types.d.ts +58 -0
- package/package.json +1 -1
- package/src/components/BaseApp.vue +16 -0
- package/src/components/BaseAppDialogs.vue +113 -0
- package/src/components/BaseAppNotifications.vue +73 -0
- package/src/components/BaseDataTable.vue +8 -8
- package/src/components/BaseDatePicker.vue +1 -1
- package/src/components/BaseDateSelect.vue +1 -1
- package/src/components/BaseDialog.vue +1 -0
- package/src/components/BaseFileUploader.vue +16 -7
- package/src/components/BaseInputLabel.vue +3 -3
- package/src/components/BaseMediaLibrary.vue +10 -10
- package/src/components/BaseTagAutocomplete.vue +4 -4
- package/src/components/index.ts +16 -1
- package/src/index.ts +23 -14
- package/src/lang/en.json +9 -8
- package/src/lang/fr.json +9 -8
- package/src/stores/dialogs.ts +45 -0
- package/src/stores/notifications.ts +47 -0
- package/src/stores/systemAlerts.ts +33 -0
- package/src/types/types.ts +67 -0
- package/dist/types/src/components/BaseLoadingPage.vue.d.ts +0 -2
- package/src/components/BaseLoadingPage.vue +0 -19
|
@@ -36,13 +36,17 @@ import { config } from '@/index';
|
|
|
36
36
|
import { PropType } from 'vue';
|
|
37
37
|
import { UploadedFile } from '@/types/UploadedFile';
|
|
38
38
|
import { toHumanList, fileSizeFormat } from '../utils';
|
|
39
|
-
|
|
39
|
+
import { useNotificationsStore } from '../stores/notifications';
|
|
40
40
|
|
|
41
41
|
const http = config.http;
|
|
42
42
|
const i18n = useI18n();
|
|
43
|
-
|
|
43
|
+
const notifications = useNotificationsStore();
|
|
44
44
|
|
|
45
45
|
const props = defineProps({
|
|
46
|
+
url: {
|
|
47
|
+
default: undefined,
|
|
48
|
+
type: String,
|
|
49
|
+
},
|
|
46
50
|
disabled: {
|
|
47
51
|
default: false,
|
|
48
52
|
type: Boolean,
|
|
@@ -91,13 +95,13 @@ async function onPictureUpload(file: File) {
|
|
|
91
95
|
|
|
92
96
|
try {
|
|
93
97
|
if (file.size > props.maxSize) {
|
|
94
|
-
|
|
98
|
+
notifications.push({
|
|
95
99
|
color: 'danger',
|
|
96
100
|
title: i18n.t('sui.error'),
|
|
97
101
|
text: i18n.t('sui.the_file_size_must_not_exceed_x', {
|
|
98
102
|
x: fileSizeFormat(props.maxSize),
|
|
99
103
|
}),
|
|
100
|
-
});
|
|
104
|
+
});
|
|
101
105
|
return;
|
|
102
106
|
}
|
|
103
107
|
|
|
@@ -109,7 +113,7 @@ async function onPictureUpload(file: File) {
|
|
|
109
113
|
props.acceptedExtensions.length
|
|
110
114
|
) {
|
|
111
115
|
if (!props.acceptedExtensions.includes(extension)) {
|
|
112
|
-
|
|
116
|
+
notifications.push({
|
|
113
117
|
color: 'danger',
|
|
114
118
|
title: i18n.t('sui.error'),
|
|
115
119
|
text:
|
|
@@ -119,7 +123,7 @@ async function onPictureUpload(file: File) {
|
|
|
119
123
|
' ' +
|
|
120
124
|
toHumanList(props.acceptedExtensions, i18n.t('sui.or')) +
|
|
121
125
|
'.',
|
|
122
|
-
});
|
|
126
|
+
});
|
|
123
127
|
return;
|
|
124
128
|
}
|
|
125
129
|
}
|
|
@@ -131,7 +135,7 @@ async function onPictureUpload(file: File) {
|
|
|
131
135
|
uploading.value = true;
|
|
132
136
|
emit('upload:start');
|
|
133
137
|
|
|
134
|
-
const response = await http.post(config.upload_url, formData);
|
|
138
|
+
const response = await http.post(props.url ?? config.upload_url, formData);
|
|
135
139
|
|
|
136
140
|
const payload = response.data as UploadedFile;
|
|
137
141
|
payload.original_file = file;
|
|
@@ -154,6 +158,11 @@ async function onPictureUpload(file: File) {
|
|
|
154
158
|
}
|
|
155
159
|
} catch (e: unknown) {
|
|
156
160
|
emit('upload:fail');
|
|
161
|
+
notifications.push({
|
|
162
|
+
color: 'danger',
|
|
163
|
+
title: i18n.t('sui.error'),
|
|
164
|
+
text: i18n.t('sui.upload_failed'),
|
|
165
|
+
});
|
|
157
166
|
} finally {
|
|
158
167
|
emit('upload:end');
|
|
159
168
|
uploading.value = false;
|
|
@@ -91,15 +91,15 @@ import { Media } from '@/types/Media';
|
|
|
91
91
|
import _, { cloneDeep, get } from 'lodash';
|
|
92
92
|
import { PropType } from 'vue';
|
|
93
93
|
import { MediaLibraryPayload } from '@/types/types';
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
import { useDialogsStore } from '../stores/dialogs';
|
|
95
|
+
import { useNotificationsStore } from '../stores/notifications';
|
|
96
96
|
import { capitalize } from 'lodash';
|
|
97
97
|
import { fileSizeFormat } from 'src/utils';
|
|
98
98
|
|
|
99
99
|
const i18n = useI18n();
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
const dialogs = useDialogsStore();
|
|
102
|
+
const notifications = useNotificationsStore();
|
|
103
103
|
|
|
104
104
|
const emit = defineEmits([
|
|
105
105
|
'update',
|
|
@@ -188,11 +188,11 @@ function onUploadSuccess(file: UploadedFile) {
|
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
if (numberOfFiles.value >= props.max && props.max > 1) {
|
|
191
|
-
|
|
191
|
+
notifications.push({
|
|
192
192
|
title: i18n.t('sui.whoops'),
|
|
193
193
|
text: i18n.t('sui.you_can_upload_up_to_n_files', { count: props.max }),
|
|
194
194
|
color: 'danger',
|
|
195
|
-
});
|
|
195
|
+
});
|
|
196
196
|
return;
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -213,25 +213,25 @@ function onUploadSuccess(file: UploadedFile) {
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
function promptRemoveUploadedFile(index: number, length = 1) {
|
|
216
|
-
|
|
216
|
+
dialogs.push({
|
|
217
217
|
title: i18n.t('sui.remove_file'),
|
|
218
218
|
message: i18n.t('sui.remove_file_description'),
|
|
219
219
|
color: 'warning',
|
|
220
220
|
onConfirm() {
|
|
221
221
|
removeUploadedFile(index, length);
|
|
222
222
|
},
|
|
223
|
-
});
|
|
223
|
+
});
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
function promptRemoveMedia(index: number) {
|
|
227
|
-
|
|
227
|
+
dialogs.push({
|
|
228
228
|
title: i18n.t('sui.remove_file'),
|
|
229
229
|
message: i18n.t('sui.remove_file_description'),
|
|
230
230
|
color: 'warning',
|
|
231
231
|
onConfirm() {
|
|
232
232
|
removeMedia(index);
|
|
233
233
|
},
|
|
234
|
-
});
|
|
234
|
+
});
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
function removeUploadedFile(index: number, length = 1) {
|
|
@@ -83,7 +83,7 @@ import { PropType, Ref, ComputedRef } from 'vue';
|
|
|
83
83
|
import { NormalizedOption, Option, OptionValue } from '@/types/types';
|
|
84
84
|
import { useInfiniteScroll } from '@vueuse/core';
|
|
85
85
|
import BaseLoadingCover from './BaseLoadingCover.vue';
|
|
86
|
-
|
|
86
|
+
import { useNotificationsStore } from '@/stores/notifications';
|
|
87
87
|
|
|
88
88
|
const props = defineProps({
|
|
89
89
|
modelValue: {
|
|
@@ -140,7 +140,7 @@ const emit = defineEmits([
|
|
|
140
140
|
]);
|
|
141
141
|
|
|
142
142
|
const i18n = useI18n();
|
|
143
|
-
|
|
143
|
+
const notifications = useNotificationsStore();
|
|
144
144
|
|
|
145
145
|
const timerId = ref(0);
|
|
146
146
|
const keywords = ref('');
|
|
@@ -308,11 +308,11 @@ const toggleOption = (option: NormalizedOption) => {
|
|
|
308
308
|
|
|
309
309
|
const addOption = (option: NormalizedOption) => {
|
|
310
310
|
if (props.max && normalizedModelValue.value.length >= props.max) {
|
|
311
|
-
|
|
311
|
+
notifications.push({
|
|
312
312
|
title: i18n.t('sui.whoops'),
|
|
313
313
|
text: i18n.t('sui.you_cannot_select_more_than_x_items', { x: props.max }),
|
|
314
314
|
color: 'warning',
|
|
315
|
-
});
|
|
315
|
+
});
|
|
316
316
|
return;
|
|
317
317
|
}
|
|
318
318
|
|
package/src/components/index.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import BaseAlert from './BaseAlert.vue';
|
|
2
|
+
import BaseApp from './BaseApp.vue';
|
|
3
|
+
import BaseAppDialogs from './BaseAppDialogs.vue';
|
|
4
|
+
import BaseAppNotifications from './BaseAppNotifications.vue';
|
|
2
5
|
import BaseAutocomplete from './BaseAutocomplete.vue';
|
|
3
6
|
import BaseAutocompleteFetch from './BaseAutocompleteFetch.vue';
|
|
4
7
|
import BaseAvatar from './BaseAvatar.vue';
|
|
@@ -16,7 +19,11 @@ import BaseDataIterator from './BaseDataIterator.vue';
|
|
|
16
19
|
import BaseDataTable from './BaseDataTable.vue';
|
|
17
20
|
import BaseDatePicker from './BaseDatePicker.vue';
|
|
18
21
|
import BaseDateSelect from './BaseDateSelect.vue';
|
|
19
|
-
|
|
22
|
+
import BaseDescriptionList from './BaseDescriptionList.vue';
|
|
23
|
+
import BaseDescriptionListItem from './BaseDescriptionListItem.vue';
|
|
24
|
+
import BaseDialog from './BaseDialog.vue';
|
|
25
|
+
import BaseFilePicker from './BaseFilePicker.vue';
|
|
26
|
+
import BaseFileUploader from './BaseFileUploader.vue';
|
|
20
27
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
21
28
|
import BaseLoadingCover from './BaseLoadingCover.vue';
|
|
22
29
|
import BaseMenu from './BaseMenu.vue';
|
|
@@ -26,6 +33,9 @@ import BaseTableColumn from './BaseTableColumn.vue';
|
|
|
26
33
|
|
|
27
34
|
export {
|
|
28
35
|
BaseAlert,
|
|
36
|
+
BaseApp,
|
|
37
|
+
BaseAppDialogs,
|
|
38
|
+
BaseAppNotifications,
|
|
29
39
|
BaseAutocomplete,
|
|
30
40
|
BaseAutocompleteFetch,
|
|
31
41
|
BaseAvatar,
|
|
@@ -43,6 +53,11 @@ export {
|
|
|
43
53
|
BaseDataTable,
|
|
44
54
|
BaseDatePicker,
|
|
45
55
|
BaseDateSelect,
|
|
56
|
+
BaseDescriptionList,
|
|
57
|
+
BaseDescriptionListItem,
|
|
58
|
+
BaseDialog,
|
|
59
|
+
BaseFilePicker,
|
|
60
|
+
BaseFileUploader,
|
|
46
61
|
BaseIcon,
|
|
47
62
|
BaseLoadingCover,
|
|
48
63
|
BaseMenu,
|
package/src/index.ts
CHANGED
|
@@ -5,12 +5,15 @@ import QueryString from 'qs';
|
|
|
5
5
|
import { createI18n, I18n } from 'vue-i18n';
|
|
6
6
|
import en from '@/lang/en.json';
|
|
7
7
|
import fr from '@/lang/fr.json';
|
|
8
|
+
import { useDialogsStore } from './stores/dialogs';
|
|
9
|
+
import { useNotificationsStore } from './stores/notifications';
|
|
10
|
+
import { useSystemAlertStore } from './stores/systemAlerts';
|
|
8
11
|
|
|
9
12
|
const messages = { en, fr };
|
|
10
13
|
|
|
11
14
|
import './assets/main.css';
|
|
12
15
|
|
|
13
|
-
interface
|
|
16
|
+
export interface Options {
|
|
14
17
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
15
18
|
i18n?: I18n<typeof messages, {}, {}, string, true>;
|
|
16
19
|
http?: AxiosInstance;
|
|
@@ -19,8 +22,10 @@ interface SprintifyUIConfig {
|
|
|
19
22
|
parseQueryString?: (params: string) => Record<string, any>;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
|
-
const
|
|
25
|
+
const config = {
|
|
23
26
|
i18n: createI18n({
|
|
27
|
+
locale: 'en',
|
|
28
|
+
fallbackLocale: 'en',
|
|
24
29
|
messages: { en, fr },
|
|
25
30
|
}),
|
|
26
31
|
http: axios.create(),
|
|
@@ -36,30 +41,30 @@ const pluginConfig = {
|
|
|
36
41
|
},
|
|
37
42
|
};
|
|
38
43
|
|
|
39
|
-
function install(app: App,
|
|
44
|
+
function install(app: App, options?: Options) {
|
|
40
45
|
for (const key in components) {
|
|
41
46
|
// @ts-expect-error Will throw
|
|
42
47
|
app.component(key, components[key]);
|
|
43
48
|
}
|
|
44
49
|
|
|
45
|
-
if (
|
|
46
|
-
|
|
50
|
+
if (options?.i18n) {
|
|
51
|
+
config.i18n = options.i18n;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
54
|
+
if (options?.http) {
|
|
55
|
+
config.http = options.http;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
if (
|
|
54
|
-
|
|
58
|
+
if (options?.upload_url) {
|
|
59
|
+
config.upload_url = options.upload_url;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
if (
|
|
58
|
-
|
|
62
|
+
if (options?.formatQueryString) {
|
|
63
|
+
config.formatQueryString = options.formatQueryString;
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
if (
|
|
62
|
-
|
|
66
|
+
if (options?.parseQueryString) {
|
|
67
|
+
config.parseQueryString = options.parseQueryString;
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
|
|
@@ -71,4 +76,8 @@ export * from './utils';
|
|
|
71
76
|
|
|
72
77
|
export { messages };
|
|
73
78
|
|
|
74
|
-
export {
|
|
79
|
+
export { config };
|
|
80
|
+
|
|
81
|
+
export { useDialogsStore };
|
|
82
|
+
export { useNotificationsStore };
|
|
83
|
+
export { useSystemAlertStore };
|
package/src/lang/en.json
CHANGED
|
@@ -38,19 +38,20 @@
|
|
|
38
38
|
"the_file_size_must_not_exceed_x": "The file size must not exceed {x}",
|
|
39
39
|
"the_file_type_is_invalid": "The file type is invalid",
|
|
40
40
|
"type_to_start_your_search": "Type to start your search",
|
|
41
|
-
"up_to_x": "Up to {x}",
|
|
42
|
-
"whoops": "Whoops",
|
|
43
|
-
"x_rows_selected": "1 item selected | {count} items selected",
|
|
44
|
-
"year": "Year",
|
|
45
|
-
"yes_delete": "Yes, delete",
|
|
46
|
-
"you_can_upload_up_to_n_files": "You can upload one file at most|You can upload up to {count} files",
|
|
47
|
-
"you_cannot_select_more_than_x_items": "You can't select more than one item|You can't select more than {x} items",
|
|
48
41
|
"units": {
|
|
49
42
|
"b": "B",
|
|
50
43
|
"gb": "GB",
|
|
51
44
|
"kb": "kB",
|
|
52
45
|
"mb": "MB",
|
|
53
46
|
"tb": "TB"
|
|
54
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"up_to_x": "Up to {x}",
|
|
49
|
+
"upload_failed": "Upload failed",
|
|
50
|
+
"whoops": "Whoops",
|
|
51
|
+
"x_rows_selected": "1 item selected | {count} items selected",
|
|
52
|
+
"year": "Year",
|
|
53
|
+
"yes_delete": "Yes, delete",
|
|
54
|
+
"you_can_upload_up_to_n_files": "You can upload one file at most|You can upload up to {count} files",
|
|
55
|
+
"you_cannot_select_more_than_x_items": "You can't select more than one item|You can't select more than {x} items"
|
|
55
56
|
}
|
|
56
57
|
}
|
package/src/lang/fr.json
CHANGED
|
@@ -38,19 +38,20 @@
|
|
|
38
38
|
"the_file_size_must_not_exceed_x": "La taille du fichier ne doit pas dépasser {x}",
|
|
39
39
|
"the_file_type_is_invalid": "Le type de fichier n'est pas valide",
|
|
40
40
|
"type_to_start_your_search": "Tapez pour lancer votre recherche",
|
|
41
|
-
"up_to_x": "Jusqu'à {x}",
|
|
42
|
-
"whoops": "Oups",
|
|
43
|
-
"x_rows_selected": "1 item sélectionné | \n{count} items sélectionnés",
|
|
44
|
-
"year": "An",
|
|
45
|
-
"yes_delete": "Oui, supprimer",
|
|
46
|
-
"you_can_upload_up_to_n_files": "Vous pouvez télécharger un fichier au maximum|Vous pouvez télécharger jusqu'à {count} fichiers",
|
|
47
|
-
"you_cannot_select_more_than_x_items": "Vous ne pouvez pas sélectionner plus de un élément|Vous ne pouvez pas sélectionner plus de {x} éléments",
|
|
48
41
|
"units": {
|
|
49
42
|
"b": "o",
|
|
50
43
|
"gb": "Go",
|
|
51
44
|
"kb": "Ko",
|
|
52
45
|
"mb": "Mo",
|
|
53
46
|
"tb": "To"
|
|
54
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"up_to_x": "Jusqu'à {x}",
|
|
49
|
+
"upload_failed": "Le téléchargement a échoué",
|
|
50
|
+
"whoops": "Oups",
|
|
51
|
+
"x_rows_selected": "1 item sélectionné | \n{count} items sélectionnés",
|
|
52
|
+
"year": "An",
|
|
53
|
+
"yes_delete": "Oui, supprimer",
|
|
54
|
+
"you_can_upload_up_to_n_files": "Vous pouvez télécharger un fichier au maximum|Vous pouvez télécharger jusqu'à {count} fichiers",
|
|
55
|
+
"you_cannot_select_more_than_x_items": "Vous ne pouvez pas sélectionner plus de un élément|Vous ne pouvez pas sélectionner plus de {x} éléments"
|
|
55
56
|
}
|
|
56
57
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { config } from '@/index';
|
|
3
|
+
import { Dialog, DialogOptions } from '../types/types';
|
|
4
|
+
|
|
5
|
+
export const useDialogsStore = defineStore('dialogs', {
|
|
6
|
+
state: () => {
|
|
7
|
+
return {
|
|
8
|
+
count: 0,
|
|
9
|
+
dialogs: [] as Dialog[],
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
actions: {
|
|
13
|
+
push(options: DialogOptions) {
|
|
14
|
+
this.count++;
|
|
15
|
+
this.dialogs.push({
|
|
16
|
+
id: this.count,
|
|
17
|
+
color: options.color ?? 'info',
|
|
18
|
+
title: options.title,
|
|
19
|
+
message: options.message,
|
|
20
|
+
confirmText: options.confirmText ?? config.i18n.global.t('sui.confirm'),
|
|
21
|
+
cancelText: options.cancelText ?? config.i18n.global.t('sui.cancel'),
|
|
22
|
+
closeOnOutsideClick: options.closeOnOutsideClick ?? true,
|
|
23
|
+
onConfirm:
|
|
24
|
+
options.onConfirm ??
|
|
25
|
+
function () {
|
|
26
|
+
return;
|
|
27
|
+
},
|
|
28
|
+
onCancel:
|
|
29
|
+
options.onCancel ??
|
|
30
|
+
function () {
|
|
31
|
+
return;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
remove(dialog: Dialog) {
|
|
36
|
+
this.dialogs.splice(
|
|
37
|
+
this.dialogs.findIndex((a) => a.id === dialog.id),
|
|
38
|
+
1
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
clear() {
|
|
42
|
+
this.dialogs = [];
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { Notification, NotificationOptions } from '../types/types';
|
|
3
|
+
|
|
4
|
+
export const useNotificationsStore = defineStore('notifications', {
|
|
5
|
+
state: () => {
|
|
6
|
+
return {
|
|
7
|
+
count: 0,
|
|
8
|
+
notifications: [] as Notification[],
|
|
9
|
+
timeouts: {} as Record<number, number>,
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
actions: {
|
|
13
|
+
push(options: NotificationOptions) {
|
|
14
|
+
this.count++;
|
|
15
|
+
|
|
16
|
+
const id = this.count;
|
|
17
|
+
|
|
18
|
+
const notification = {
|
|
19
|
+
id: id,
|
|
20
|
+
color: options.color ?? 'info',
|
|
21
|
+
title: options.title,
|
|
22
|
+
text: options.text,
|
|
23
|
+
duration: options.duration ?? 3000,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
this.notifications.push(notification);
|
|
27
|
+
|
|
28
|
+
this.timeouts[id] = setTimeout(() => {
|
|
29
|
+
this.remove(notification);
|
|
30
|
+
}, notification.duration);
|
|
31
|
+
},
|
|
32
|
+
remove(notification: Notification) {
|
|
33
|
+
this.notifications.splice(
|
|
34
|
+
this.notifications.findIndex((n) => n.id === notification.id),
|
|
35
|
+
1
|
|
36
|
+
);
|
|
37
|
+
clearTimeout(this.timeouts[notification.id]);
|
|
38
|
+
},
|
|
39
|
+
clear() {
|
|
40
|
+
this.notifications = [];
|
|
41
|
+
Object.values(this.timeouts).forEach((timeout) => {
|
|
42
|
+
clearTimeout(timeout);
|
|
43
|
+
});
|
|
44
|
+
this.timeouts = [];
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineStore } from 'pinia';
|
|
2
|
+
import { SystemAlert, SystemAlertOptions } from '../types/types';
|
|
3
|
+
|
|
4
|
+
export const useSystemAlertStore = defineStore('systemAlerts', {
|
|
5
|
+
state: () => {
|
|
6
|
+
return {
|
|
7
|
+
count: 0,
|
|
8
|
+
systemAlerts: [] as SystemAlert[],
|
|
9
|
+
};
|
|
10
|
+
},
|
|
11
|
+
actions: {
|
|
12
|
+
push(systemAlert: SystemAlertOptions) {
|
|
13
|
+
this.count++;
|
|
14
|
+
this.systemAlerts.push({
|
|
15
|
+
id: this.count,
|
|
16
|
+
color: systemAlert.color ?? 'info',
|
|
17
|
+
message: systemAlert.message,
|
|
18
|
+
to: systemAlert.to,
|
|
19
|
+
action: systemAlert.action,
|
|
20
|
+
closable: systemAlert.closable ?? false,
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
remove(systemAlert: SystemAlert) {
|
|
24
|
+
this.systemAlerts.splice(
|
|
25
|
+
this.systemAlerts.findIndex((a) => a.id === systemAlert.id),
|
|
26
|
+
1
|
|
27
|
+
);
|
|
28
|
+
},
|
|
29
|
+
clear() {
|
|
30
|
+
this.systemAlerts = [];
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
});
|
package/src/types/types.ts
CHANGED
|
@@ -110,3 +110,70 @@ export interface BaseTableColumn {
|
|
|
110
110
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
111
|
tdAttrs: (row: Row, column: BaseTableColumn) => Record<string, any>;
|
|
112
112
|
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* System alert
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
export interface SystemAlertOptions {
|
|
119
|
+
color?: 'info' | 'success' | 'danger' | 'warning';
|
|
120
|
+
message: string;
|
|
121
|
+
to?: RouteLocationRaw;
|
|
122
|
+
action?: () => void;
|
|
123
|
+
closable?: boolean;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export interface SystemAlert {
|
|
127
|
+
id: number;
|
|
128
|
+
color: 'info' | 'success' | 'danger' | 'warning';
|
|
129
|
+
message: string;
|
|
130
|
+
to?: RouteLocationRaw;
|
|
131
|
+
action?: () => void;
|
|
132
|
+
closable: boolean;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Dialog
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
export interface DialogOptions {
|
|
140
|
+
color?: 'info' | 'success' | 'danger' | 'warning';
|
|
141
|
+
title: string;
|
|
142
|
+
message: string;
|
|
143
|
+
confirmText?: string;
|
|
144
|
+
cancelText?: string;
|
|
145
|
+
closeOnOutsideClick?: boolean;
|
|
146
|
+
onConfirm?: () => void;
|
|
147
|
+
onCancel?: () => void;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export interface Dialog {
|
|
151
|
+
id: number;
|
|
152
|
+
color: 'info' | 'success' | 'danger' | 'warning';
|
|
153
|
+
title: string;
|
|
154
|
+
message: string;
|
|
155
|
+
confirmText: string;
|
|
156
|
+
cancelText: string;
|
|
157
|
+
closeOnOutsideClick: boolean;
|
|
158
|
+
onConfirm: () => void;
|
|
159
|
+
onCancel: () => void;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Notification
|
|
164
|
+
*/
|
|
165
|
+
|
|
166
|
+
export interface NotificationOptions {
|
|
167
|
+
title: string;
|
|
168
|
+
text: string;
|
|
169
|
+
color?: 'info' | 'success' | 'danger' | 'warning';
|
|
170
|
+
duration?: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface Notification {
|
|
174
|
+
id: number;
|
|
175
|
+
title: string;
|
|
176
|
+
text: string;
|
|
177
|
+
color: 'info' | 'success' | 'danger' | 'warning';
|
|
178
|
+
duration: number;
|
|
179
|
+
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
class="fixed inset-0 z-loading flex h-full w-full items-center justify-center bg-white"
|
|
4
|
-
>
|
|
5
|
-
<div class="flex flex-col items-center">
|
|
6
|
-
<img
|
|
7
|
-
:src="'/img/logo/icon-color.svg'"
|
|
8
|
-
alt="Loading"
|
|
9
|
-
class="mb-14 w-16 animate-pulse"
|
|
10
|
-
/>
|
|
11
|
-
<svg class="h-6 w-6 animate-spin text-primary-500" viewBox="0 0 24 24">
|
|
12
|
-
<path
|
|
13
|
-
fill="currentColor"
|
|
14
|
-
d="M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z"
|
|
15
|
-
/>
|
|
16
|
-
</svg>
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
</template>
|