sprintify-ui 0.1.14 → 0.1.16
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 +1 -26
- package/dist/sprintify-ui.es.js +11391 -11329
- package/dist/style.css +1 -1
- package/dist/types/src/components/BaseAutocomplete.vue.d.ts +1 -1
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +2 -2
- package/dist/types/src/components/BaseBelongsTo.vue.d.ts +1 -1
- package/dist/types/src/components/BaseCounter.vue.d.ts +4 -3
- package/dist/types/src/components/BaseDatePicker.vue.d.ts +1 -1
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +1 -1
- package/dist/types/src/components/BaseHeader.vue.d.ts +6 -1
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMediaListItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMenuItem.vue.d.ts +4 -3
- package/dist/types/src/components/BaseNumber.vue.d.ts +3 -3
- package/dist/types/src/components/BaseSwitch.vue.d.ts +0 -27
- package/dist/types/src/components/BaseTableColumn.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +1 -1
- package/dist/types/src/composables/mediaQuery.d.ts +2 -2
- package/dist/types/src/i18n/index.d.ts +1 -0
- package/dist/types/src/index.d.ts +0 -178
- package/dist/types/src/stores/i18n.d.ts +5 -0
- package/dist/types/src/types/index.d.ts +3 -2
- package/package.json +7 -6
- package/src/components/BaseActionItemButton.vue +2 -0
- package/src/components/BaseAddressForm.vue +8 -7
- package/src/components/BaseAutocomplete.vue +3 -3
- package/src/components/BaseAutocompleteDrawer.vue +2 -1
- package/src/components/BaseAutocompleteFetch.vue +2 -1
- package/src/components/BaseCharacterCounter.vue +2 -1
- package/src/components/BaseClipboard.vue +4 -2
- package/src/components/BaseCounter.stories.js +1 -1
- package/src/components/BaseCounter.vue +5 -3
- package/src/components/BaseCropper.vue +2 -5
- package/src/components/BaseCropperModal.vue +3 -2
- package/src/components/BaseDataIterator.vue +6 -7
- package/src/components/BaseDataTable.vue +14 -14
- package/src/components/BaseDatePicker.vue +4 -4
- package/src/components/BaseDateSelect.vue +10 -10
- package/src/components/BaseDialog.vue +5 -6
- package/src/components/BaseDisplayRelativeTime.vue +6 -6
- package/src/components/BaseFilePicker.vue +7 -8
- package/src/components/BaseFileUploader.vue +3 -3
- package/src/components/BaseForm.vue +3 -3
- package/src/components/BaseHeader.stories.js +12 -5
- package/src/components/BaseHeader.vue +73 -74
- package/src/components/BaseIconPicker.vue +2 -1
- package/src/components/BaseLayoutNotificationDropdown.vue +3 -2
- package/src/components/BaseMediaLibrary.vue +8 -11
- package/src/components/BaseMediaListItem.vue +4 -3
- package/src/components/BaseMenuItem.vue +4 -3
- package/src/components/BaseNumber.vue +25 -5
- package/src/components/BasePagination.vue +4 -3
- package/src/components/BaseReadMore.vue +2 -1
- package/src/components/BaseSelect.vue +3 -2
- package/src/components/BaseSwitch.stories.js +5 -2
- package/src/components/BaseSwitch.vue +9 -36
- package/src/components/BaseTagAutocomplete.vue +4 -4
- package/src/components/BaseTagAutocompleteFetch.vue +3 -2
- package/src/composables/mediaQuery.ts +2 -2
- package/src/i18n/index.ts +60 -0
- package/src/index.ts +11 -11
- package/src/stores/dialogs.ts +3 -3
- package/src/stores/i18n.ts +14 -0
- package/src/types/index.ts +11 -2
- package/src/utils/fileSizeFormat.ts +6 -6
- package/src/utils/toHumanList.ts +2 -2
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
<input
|
|
20
20
|
v-model="keywords"
|
|
21
21
|
type="text"
|
|
22
|
-
:placeholder="
|
|
22
|
+
:placeholder="t('sui.search') + '...'"
|
|
23
23
|
class="min-w-[40px] grow rounded-r border-slate-300 py-0 px-2 focus:border-blue-500 focus:ring-2 focus:ring-blue-300 sm:text-sm"
|
|
24
24
|
/>
|
|
25
25
|
</div>
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
<script lang="ts" setup>
|
|
50
50
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
51
|
+
import { t } from '@/i18n';
|
|
51
52
|
|
|
52
53
|
const props = withDefaults(
|
|
53
54
|
defineProps<{
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
class="mx-auto mb-2 h-8 w-8 text-slate-400"
|
|
42
42
|
></BaseIcon>
|
|
43
43
|
<p class="text-center text-sm text-slate-700">
|
|
44
|
-
{{
|
|
44
|
+
{{ t('sui.notifications_empty') }}
|
|
45
45
|
</p>
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
{{
|
|
60
60
|
notificationsConfig.footerLabel
|
|
61
61
|
? notificationsConfig.footerLabel
|
|
62
|
-
:
|
|
62
|
+
: t('sui.see_all_notifications')
|
|
63
63
|
}}
|
|
64
64
|
</div>
|
|
65
65
|
</RouterLink>
|
|
@@ -79,6 +79,7 @@ import { useBreakpoints } from '@/composables/breakpoints';
|
|
|
79
79
|
import { NotificationsConfig } from '../types';
|
|
80
80
|
import { MenuItem } from '@headlessui/vue';
|
|
81
81
|
import { Notification } from '@/types/Notification';
|
|
82
|
+
import { t } from '@/i18n';
|
|
82
83
|
|
|
83
84
|
const emit = defineEmits(['click', 'open']);
|
|
84
85
|
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
/>
|
|
39
39
|
<div class="text-center">
|
|
40
40
|
<p class="mb-0 text-sm font-medium leading-tight">
|
|
41
|
-
{{
|
|
41
|
+
{{ t('sui.drop_or_click_to_upload') }}
|
|
42
42
|
</p>
|
|
43
43
|
|
|
44
44
|
<div class="mt-1 text-xs leading-tight text-slate-500">
|
|
@@ -110,8 +110,7 @@ import { BaseIcon } from '.';
|
|
|
110
110
|
import BaseMediaList from './BaseMediaList.vue';
|
|
111
111
|
import BaseMediaPictures from './BaseMediaPictures.vue';
|
|
112
112
|
import BaseMediaGallery from './BaseMediaGallery.vue';
|
|
113
|
-
|
|
114
|
-
const i18n = useI18n();
|
|
113
|
+
import { t } from '@/i18n';
|
|
115
114
|
|
|
116
115
|
const dialogs = useDialogsStore();
|
|
117
116
|
const notifications = useNotificationsStore();
|
|
@@ -228,15 +227,13 @@ const normalizedMax = computed(() => {
|
|
|
228
227
|
});
|
|
229
228
|
|
|
230
229
|
const maxFileText = computed(() => {
|
|
231
|
-
return
|
|
230
|
+
return t('sui.you_can_upload_up_to_n_files', {
|
|
232
231
|
count: normalizedMax.value,
|
|
233
232
|
});
|
|
234
233
|
});
|
|
235
234
|
|
|
236
235
|
const maxFileSize = computed(() => {
|
|
237
|
-
return capitalize(
|
|
238
|
-
i18n.t('sui.up_to_x', { x: fileSizeFormat(props.maxSize) })
|
|
239
|
-
);
|
|
236
|
+
return capitalize(t('sui.up_to_x', { x: fileSizeFormat(props.maxSize) }));
|
|
240
237
|
});
|
|
241
238
|
|
|
242
239
|
// Upload
|
|
@@ -252,8 +249,8 @@ function onUploadSuccess(file: UploadedFile) {
|
|
|
252
249
|
normalizedMax.value > 1
|
|
253
250
|
) {
|
|
254
251
|
notifications.push({
|
|
255
|
-
title:
|
|
256
|
-
text:
|
|
252
|
+
title: t('sui.whoops'),
|
|
253
|
+
text: t('sui.you_can_upload_up_to_n_files', {
|
|
257
254
|
count: normalizedMax.value,
|
|
258
255
|
}),
|
|
259
256
|
color: 'danger',
|
|
@@ -279,8 +276,8 @@ function onUploadSuccess(file: UploadedFile) {
|
|
|
279
276
|
|
|
280
277
|
function promptRemove(index: number, length = 1) {
|
|
281
278
|
dialogs.push({
|
|
282
|
-
title:
|
|
283
|
-
message:
|
|
279
|
+
title: t('sui.remove_file'),
|
|
280
|
+
message: t('sui.remove_file_description'),
|
|
284
281
|
color: 'warning',
|
|
285
282
|
onConfirm() {
|
|
286
283
|
removeByIndex(index, length);
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
class="h-10 shrink-0 pr-2 pl-3 text-sm text-blue-600"
|
|
55
55
|
@click="saveName"
|
|
56
56
|
>
|
|
57
|
-
{{
|
|
57
|
+
{{ t('sui.save') }}
|
|
58
58
|
</button>
|
|
59
59
|
</div>
|
|
60
60
|
</div>
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
@click="$emit('remove')"
|
|
69
69
|
>
|
|
70
70
|
<span class="hidden sm:inline">
|
|
71
|
-
{{
|
|
71
|
+
{{ t('sui.delete') }}
|
|
72
72
|
</span>
|
|
73
73
|
<BaseIcon
|
|
74
74
|
icon="heroicons-solid:x"
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
target="_blank"
|
|
83
83
|
>
|
|
84
84
|
<span class="hidden sm:inline">
|
|
85
|
-
{{
|
|
85
|
+
{{ t('sui.download') }}
|
|
86
86
|
</span>
|
|
87
87
|
<BaseIcon
|
|
88
88
|
icon="heroicons-solid:download"
|
|
@@ -100,6 +100,7 @@ import { UploadedFile } from '@/types/UploadedFile';
|
|
|
100
100
|
import { PropType } from 'vue';
|
|
101
101
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
102
102
|
import { cloneDeep } from 'lodash';
|
|
103
|
+
import { t } from '@/i18n';
|
|
103
104
|
|
|
104
105
|
const emit = defineEmits(['remove', 'update', 'save:name']);
|
|
105
106
|
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<script lang="ts" setup>
|
|
14
14
|
import { PropType } from 'vue';
|
|
15
15
|
import BaseCounter from './BaseCounter.vue';
|
|
16
|
+
import { ActionColors } from '@/types';
|
|
16
17
|
|
|
17
18
|
const props = defineProps({
|
|
18
19
|
label: {
|
|
@@ -33,9 +34,7 @@ const props = defineProps({
|
|
|
33
34
|
},
|
|
34
35
|
color: {
|
|
35
36
|
default: 'dark',
|
|
36
|
-
type: String as PropType<
|
|
37
|
-
'dark' | 'light' | 'danger' | 'success' | 'warning' | 'primary'
|
|
38
|
-
>,
|
|
37
|
+
type: String as PropType<ActionColors>,
|
|
39
38
|
},
|
|
40
39
|
size: {
|
|
41
40
|
default: 'md',
|
|
@@ -56,6 +55,8 @@ const textColor = computed((): string => {
|
|
|
56
55
|
return 'text-yellow-600';
|
|
57
56
|
} else if (props.color == 'primary') {
|
|
58
57
|
return 'text-primary-600';
|
|
58
|
+
} else if (props.color == 'secondary') {
|
|
59
|
+
return 'text-slate-600';
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
return '';
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
>
|
|
15
15
|
<span v-if="tooBig"> Maximum {{ max }} </span>
|
|
16
16
|
<span v-else-if="tooSmall"> Minimum {{ min }} </span>
|
|
17
|
+
<span v-else-if="tooPrecise">
|
|
18
|
+
{{ t('sui.maximum_x_decimal_places', { count: precision }) }}
|
|
19
|
+
</span>
|
|
17
20
|
<span v-else>
|
|
18
|
-
{{
|
|
21
|
+
{{ t('sui.invalid_value') }}
|
|
19
22
|
</span>
|
|
20
23
|
</div>
|
|
21
24
|
</div>
|
|
@@ -74,6 +77,7 @@ import { useField } from '@/composables/field';
|
|
|
74
77
|
import { isNumber, round } from 'lodash';
|
|
75
78
|
import { PropType } from 'vue';
|
|
76
79
|
import { BaseIcon } from '.';
|
|
80
|
+
import { t } from '@/i18n';
|
|
77
81
|
|
|
78
82
|
const AUTO_CORRECT_TIMEOUT = 2000;
|
|
79
83
|
const SHOW_INVALID_INPUT_TIMEOUT = 500;
|
|
@@ -183,22 +187,38 @@ const realValueInternal = computed<number | null>(() => {
|
|
|
183
187
|
return convertToNumber(valueInternal.value);
|
|
184
188
|
});
|
|
185
189
|
|
|
190
|
+
const realValueInternalAsString = computed<string>(() => {
|
|
191
|
+
if (realValueInternal.value === null) return '';
|
|
192
|
+
return realValueInternal.value.toLocaleString('fullwide', {
|
|
193
|
+
useGrouping: false,
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
186
197
|
const invalidInput = computed(() => {
|
|
187
198
|
if (realValueInternal.value == null && valueInternal.value == '') {
|
|
188
199
|
return false;
|
|
189
200
|
}
|
|
190
201
|
|
|
191
|
-
return
|
|
202
|
+
return realValueInternalAsString.value != (valueInternal.value ?? '');
|
|
192
203
|
});
|
|
193
204
|
|
|
194
205
|
const tooBig = computed(() => {
|
|
195
|
-
if (
|
|
196
|
-
return hasMax.value &&
|
|
206
|
+
if (realValueInternal.value === null) return false;
|
|
207
|
+
return hasMax.value && realValueInternal.value > (props.max as number);
|
|
197
208
|
});
|
|
198
209
|
|
|
199
210
|
const tooSmall = computed(() => {
|
|
211
|
+
if (realValueInternal.value === null) return false;
|
|
212
|
+
return hasMin.value && realValueInternal.value < (props.min as number);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const tooPrecise = computed(() => {
|
|
200
216
|
if (valueInternal.value === null) return false;
|
|
201
|
-
|
|
217
|
+
const parts = (valueInternal.value + '').split('.');
|
|
218
|
+
|
|
219
|
+
if (parts.length === 1) return false;
|
|
220
|
+
|
|
221
|
+
return parts[1].length > precision.value;
|
|
202
222
|
});
|
|
203
223
|
|
|
204
224
|
valueInternal.value = convertToNumber(props.modelValue);
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
class="mx-3 flex shrink-0 items-center justify-end"
|
|
42
42
|
>
|
|
43
43
|
<span class="mr-2 text-sm font-normal text-slate-500">
|
|
44
|
-
{{
|
|
44
|
+
{{ t('sui.page') }}
|
|
45
45
|
</span>
|
|
46
46
|
<input
|
|
47
47
|
v-model="manualPageMobile"
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
@blur="setPageFromManualPageMobile"
|
|
56
56
|
/>
|
|
57
57
|
<span class="ml-2 text-sm font-normal text-slate-500">
|
|
58
|
-
{{
|
|
58
|
+
{{ t('sui.of') }} {{ lastPage }}
|
|
59
59
|
</span>
|
|
60
60
|
</div>
|
|
61
61
|
<div class="-mt-px flex flex-1 justify-end">
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
class="mt-3 ml-4 flex shrink-0 items-center justify-end"
|
|
77
77
|
>
|
|
78
78
|
<span class="mr-3 text-sm font-medium text-slate-500">
|
|
79
|
-
{{
|
|
79
|
+
{{ t('sui.go_to_page') }}
|
|
80
80
|
</span>
|
|
81
81
|
<input
|
|
82
82
|
v-model="manualPage"
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
<script lang="ts" setup>
|
|
97
97
|
import { useResizeObserver } from '@vueuse/core';
|
|
98
98
|
import { debounce, isNumber, range } from 'lodash';
|
|
99
|
+
import { t } from '@/i18n';
|
|
99
100
|
|
|
100
101
|
const props = defineProps({
|
|
101
102
|
modelValue: {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
class="mt-1 inline appearance-none border-b border-dashed border-slate-400 bg-transparent px-0.5 py-0 text-slate-900 hover:text-slate-600"
|
|
14
14
|
@click="showMore = true"
|
|
15
15
|
>
|
|
16
|
-
<span class="text-base font-medium">{{
|
|
16
|
+
<span class="text-base font-medium">{{ t('sui.read_more') }}</span>
|
|
17
17
|
</button>
|
|
18
18
|
</div>
|
|
19
19
|
</template>
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
<script lang="ts" setup>
|
|
22
22
|
import { useMutationObserver } from '@vueuse/core';
|
|
23
23
|
import { StyleValue } from 'vue';
|
|
24
|
+
import { t } from '@/i18n';
|
|
24
25
|
|
|
25
26
|
const content = ref<null | HTMLParagraphElement>(null);
|
|
26
27
|
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
>
|
|
15
15
|
<template v-if="requiredInternal">
|
|
16
16
|
<option disabled hidden :value="EMPTY_VALUE_INTERNAL">
|
|
17
|
-
{{ placeholder ? placeholder :
|
|
17
|
+
{{ placeholder ? placeholder : t('sui.select_an_option') }}
|
|
18
18
|
</option>
|
|
19
19
|
</template>
|
|
20
20
|
<template v-else>
|
|
21
21
|
<option :value="EMPTY_VALUE_INTERNAL">
|
|
22
|
-
{{ placeholder ? placeholder :
|
|
22
|
+
{{ placeholder ? placeholder : t('sui.select_an_option') }}
|
|
23
23
|
</option>
|
|
24
24
|
</template>
|
|
25
25
|
|
|
@@ -43,6 +43,7 @@ import { get, isArray, isEqual } from 'lodash';
|
|
|
43
43
|
import { useMutationObserver } from '@vueuse/core';
|
|
44
44
|
import { useField } from '@/composables/field';
|
|
45
45
|
import { NormalizedOption, OptionValue, Option } from '@/types';
|
|
46
|
+
import { t } from '@/i18n';
|
|
46
47
|
|
|
47
48
|
type SelectOption = string | number | null;
|
|
48
49
|
|
|
@@ -118,11 +118,14 @@ const Icons = (args) => ({
|
|
|
118
118
|
return { args, value };
|
|
119
119
|
},
|
|
120
120
|
template: `
|
|
121
|
-
<BaseSwitch v-model="value"
|
|
121
|
+
<BaseSwitch v-model="value" v-bind="args">
|
|
122
122
|
<span class="text-slate-600">Label</span>
|
|
123
123
|
</BaseSwitch>
|
|
124
124
|
`,
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
export const WithIcons = Icons.bind({});
|
|
128
|
-
WithIcons.args = {
|
|
128
|
+
WithIcons.args = {
|
|
129
|
+
checkedIcon: 'heroicons-solid:check',
|
|
130
|
+
unCheckedIcon: 'heroicons-solid:x',
|
|
131
|
+
};
|
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
height: sizePx + 'px',
|
|
21
21
|
width: sizePx + 'px',
|
|
22
22
|
transform: `translateX(${translateX}px)`,
|
|
23
|
-
color: iconColor,
|
|
24
23
|
fontSize: sizePx - 7 + 'px',
|
|
25
24
|
}"
|
|
26
|
-
class="flex items-center justify-center
|
|
25
|
+
class="flex items-center justify-center transition duration-200 ease-in-out bg-white rounded-full shadow pointer-events-none text-slate-500 ring-0"
|
|
27
26
|
>
|
|
28
|
-
<BaseIcon v-if="
|
|
27
|
+
<BaseIcon v-if="icon" :icon="icon" />
|
|
29
28
|
</span>
|
|
30
29
|
</Switch>
|
|
31
30
|
<SwitchLabel v-if="$slots.default" class="cursor-pointer">
|
|
@@ -70,24 +69,12 @@ const props = defineProps({
|
|
|
70
69
|
default: false,
|
|
71
70
|
type: Boolean,
|
|
72
71
|
},
|
|
73
|
-
hasIcon: {
|
|
74
|
-
default: false,
|
|
75
|
-
type: Boolean,
|
|
76
|
-
},
|
|
77
72
|
checkedIcon: {
|
|
78
|
-
default: '
|
|
73
|
+
default: '',
|
|
79
74
|
type: String,
|
|
80
75
|
},
|
|
81
76
|
unCheckedIcon: {
|
|
82
|
-
default: '
|
|
83
|
-
type: String,
|
|
84
|
-
},
|
|
85
|
-
checkedIconColor: {
|
|
86
|
-
default: '#9ca3af',
|
|
87
|
-
type: String,
|
|
88
|
-
},
|
|
89
|
-
unCheckedIconColor: {
|
|
90
|
-
default: '#9ca3af',
|
|
77
|
+
default: '',
|
|
91
78
|
type: String,
|
|
92
79
|
},
|
|
93
80
|
});
|
|
@@ -206,26 +193,12 @@ const translateX = computed(() => {
|
|
|
206
193
|
return padding.value;
|
|
207
194
|
});
|
|
208
195
|
|
|
209
|
-
const iconColor = computed(() => {
|
|
210
|
-
if (props.hasIcon) {
|
|
211
|
-
if (props.modelValue) {
|
|
212
|
-
return props.checkedIconColor;
|
|
213
|
-
}
|
|
214
|
-
if (!props.modelValue) {
|
|
215
|
-
return props.unCheckedIconColor;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return '';
|
|
219
|
-
});
|
|
220
|
-
|
|
221
196
|
const icon = computed(() => {
|
|
222
|
-
if (props.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return props.unCheckedIcon;
|
|
228
|
-
}
|
|
197
|
+
if (props.modelValue && props.checkedIcon) {
|
|
198
|
+
return props.checkedIcon;
|
|
199
|
+
}
|
|
200
|
+
if (!props.modelValue && props.unCheckedIcon) {
|
|
201
|
+
return props.unCheckedIcon;
|
|
229
202
|
}
|
|
230
203
|
return null;
|
|
231
204
|
});
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
ref="inputElement"
|
|
39
39
|
:value="keywords"
|
|
40
40
|
type="text"
|
|
41
|
-
:placeholder="placeholder ? placeholder :
|
|
41
|
+
:placeholder="placeholder ? placeholder : t('sui.select_an_item')"
|
|
42
42
|
class="w-full min-w-[50px] border-none p-0 pl-1 shadow-none outline-none focus:border-none focus:shadow-none focus:outline-none focus:ring-0 disabled:cursor-not-allowed"
|
|
43
43
|
:class="[inputClass]"
|
|
44
44
|
autocomplete="off"
|
|
@@ -96,8 +96,8 @@ import { useField } from '@/composables/field';
|
|
|
96
96
|
import { useClickOutside } from '@/composables/clickOutside';
|
|
97
97
|
import { useNotificationsStore } from '@/stores/notifications';
|
|
98
98
|
import BaseAutocompleteDrawer from './BaseAutocompleteDrawer.vue';
|
|
99
|
+
import { t } from '@/i18n';
|
|
99
100
|
|
|
100
|
-
const i18n = useI18n();
|
|
101
101
|
const notifications = useNotificationsStore();
|
|
102
102
|
|
|
103
103
|
const props = defineProps({
|
|
@@ -283,8 +283,8 @@ const onSelect = (option: NormalizedOption) => {
|
|
|
283
283
|
|
|
284
284
|
if (props.max && normalizedModelValue.value.length >= props.max) {
|
|
285
285
|
notifications.push({
|
|
286
|
-
title:
|
|
287
|
-
text:
|
|
286
|
+
title: t('sui.whoops'),
|
|
287
|
+
text: t('sui.you_cannot_select_more_than_x_items', {
|
|
288
288
|
count: props.max,
|
|
289
289
|
}),
|
|
290
290
|
color: 'warning',
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
v-if="firstSearch"
|
|
32
32
|
class="flex h-[80px] items-center justify-center px-3 text-center text-base leading-tight text-slate-600"
|
|
33
33
|
>
|
|
34
|
-
{{
|
|
34
|
+
{{ t('sui.nothing_found') }}
|
|
35
35
|
</div>
|
|
36
36
|
</slot>
|
|
37
37
|
</template>
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
</template>
|
|
40
40
|
|
|
41
41
|
<script lang="ts" setup>
|
|
42
|
-
import { debounce,
|
|
42
|
+
import { debounce, throttle } from 'lodash';
|
|
43
43
|
import { config } from '@/index';
|
|
44
44
|
import { PropType } from 'vue';
|
|
45
45
|
import {
|
|
@@ -50,6 +50,7 @@ import {
|
|
|
50
50
|
} from '@/types';
|
|
51
51
|
import BaseTagAutocomplete from './BaseTagAutocomplete.vue';
|
|
52
52
|
import { useHasPaginatedData } from '@/composables/paginatedData';
|
|
53
|
+
import { t } from '@/i18n';
|
|
53
54
|
|
|
54
55
|
const props = defineProps({
|
|
55
56
|
modelValue: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ref, watchEffect } from 'vue';
|
|
2
|
-
import type {
|
|
2
|
+
import type { MaybeRefOrGetter } from '@vueuse/shared';
|
|
3
3
|
import { resolveRef, tryOnScopeDispose } from '@vueuse/shared';
|
|
4
4
|
|
|
5
|
-
export function useMediaQuery(query:
|
|
5
|
+
export function useMediaQuery(query: MaybeRefOrGetter<string>) {
|
|
6
6
|
const isSupported = () =>
|
|
7
7
|
window && 'matchMedia' in window && typeof window.matchMedia === 'function';
|
|
8
8
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useI18nStore } from '@/stores/i18n';
|
|
2
|
+
import en from '@/lang/en.json';
|
|
3
|
+
import fr from '@/lang/fr.json';
|
|
4
|
+
import { get } from 'lodash';
|
|
5
|
+
|
|
6
|
+
export function t(key: string, args?: Record<string, any> | undefined): string {
|
|
7
|
+
const value = getTranslationValue(key);
|
|
8
|
+
|
|
9
|
+
return replaceArgs(value, args);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getCurrentLocale() {
|
|
13
|
+
try {
|
|
14
|
+
const i18nStore = useI18nStore();
|
|
15
|
+
return i18nStore.locale;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.error(error);
|
|
18
|
+
return 'en';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getTranslationValue(key: string) {
|
|
23
|
+
const locale = getCurrentLocale();
|
|
24
|
+
|
|
25
|
+
if (locale === 'fr') {
|
|
26
|
+
const frValue = get(fr, key);
|
|
27
|
+
if (frValue) return frValue;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return get(en, key, key);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function replaceArgs(
|
|
34
|
+
value: string,
|
|
35
|
+
args: Record<string, any> | undefined
|
|
36
|
+
): string {
|
|
37
|
+
let result = value;
|
|
38
|
+
|
|
39
|
+
if (!args) return result;
|
|
40
|
+
|
|
41
|
+
if (args.count !== undefined && value.includes('|')) {
|
|
42
|
+
const parts = value.split('|');
|
|
43
|
+
|
|
44
|
+
if (parts.length == 2) {
|
|
45
|
+
const [singular, plural] = value.split('|');
|
|
46
|
+
result = args.count > 1 ? plural : singular;
|
|
47
|
+
} else if (parts.length == 3) {
|
|
48
|
+
const [zero, singular, plural] = value.split('|');
|
|
49
|
+
result = args.count == 0 ? zero : args.count > 1 ? plural : singular;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
result.trim();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
Object.keys(args).forEach((key: any) => {
|
|
56
|
+
result = result.replace(`{${key}}`, args[key]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return result;
|
|
60
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,6 @@ import axios, { AxiosInstance } from 'axios';
|
|
|
2
2
|
import { App } from 'vue';
|
|
3
3
|
import * as components from './components';
|
|
4
4
|
import QueryString from 'qs';
|
|
5
|
-
import { createI18n, I18n } from 'vue-i18n';
|
|
6
5
|
import en from '@/lang/en.json';
|
|
7
6
|
import fr from '@/lang/fr.json';
|
|
8
7
|
import { useDialogsStore } from './stores/dialogs';
|
|
@@ -17,10 +16,10 @@ import './assets/main.css';
|
|
|
17
16
|
import { Locales } from './types';
|
|
18
17
|
import { Country } from './types/Country';
|
|
19
18
|
import { Region } from './types/Region';
|
|
19
|
+
import { useI18nStore } from './stores/i18n';
|
|
20
20
|
|
|
21
21
|
export interface Options {
|
|
22
22
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
23
|
-
i18n?: I18n<typeof messages, {}, {}, string, true>;
|
|
24
23
|
http?: AxiosInstance;
|
|
25
24
|
upload_url?: string;
|
|
26
25
|
locales?: Locales;
|
|
@@ -31,11 +30,6 @@ export interface Options {
|
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
const config = {
|
|
34
|
-
i18n: createI18n({
|
|
35
|
-
locale: 'en',
|
|
36
|
-
fallbackLocale: 'en',
|
|
37
|
-
messages: { en, fr },
|
|
38
|
-
}),
|
|
39
33
|
http: axios.create(),
|
|
40
34
|
locales: {
|
|
41
35
|
en: 'English',
|
|
@@ -61,10 +55,6 @@ function install(app: App, options?: Options) {
|
|
|
61
55
|
app.component(key, components[key]);
|
|
62
56
|
}
|
|
63
57
|
|
|
64
|
-
if (options?.i18n) {
|
|
65
|
-
config.i18n = options.i18n;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
58
|
if (options?.http) {
|
|
69
59
|
config.http = options.http;
|
|
70
60
|
}
|
|
@@ -92,6 +82,16 @@ function install(app: App, options?: Options) {
|
|
|
92
82
|
if (options?.regions) {
|
|
93
83
|
config.regions = options.regions;
|
|
94
84
|
}
|
|
85
|
+
|
|
86
|
+
if (app.config.globalProperties.$i18n) {
|
|
87
|
+
watch(
|
|
88
|
+
() => app.config.globalProperties.$i18n.locale,
|
|
89
|
+
(locale) => {
|
|
90
|
+
useI18nStore().set(locale);
|
|
91
|
+
},
|
|
92
|
+
{ immediate: true }
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export default { install };
|
package/src/stores/dialogs.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineStore } from 'pinia';
|
|
2
|
-
import { config } from '@/index';
|
|
3
2
|
import { Dialog, DialogOptions } from '../types';
|
|
3
|
+
import { t } from '@/i18n';
|
|
4
4
|
|
|
5
5
|
export const useDialogsStore = defineStore('dialogs', {
|
|
6
6
|
state: () => {
|
|
@@ -17,8 +17,8 @@ export const useDialogsStore = defineStore('dialogs', {
|
|
|
17
17
|
color: options.color ?? 'info',
|
|
18
18
|
title: options.title,
|
|
19
19
|
message: options.message,
|
|
20
|
-
confirmText: options.confirmText ??
|
|
21
|
-
cancelText: options.cancelText ??
|
|
20
|
+
confirmText: options.confirmText ?? t('sui.confirm'),
|
|
21
|
+
cancelText: options.cancelText ?? t('sui.cancel'),
|
|
22
22
|
closeOnOutsideClick: options.closeOnOutsideClick ?? true,
|
|
23
23
|
onConfirm:
|
|
24
24
|
options.onConfirm ??
|
package/src/types/index.ts
CHANGED
|
@@ -65,6 +65,15 @@ export interface PaginatedCollection extends PaginationMetadata {
|
|
|
65
65
|
data: Collection;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
export type ActionColors =
|
|
69
|
+
| 'dark'
|
|
70
|
+
| 'light'
|
|
71
|
+
| 'danger'
|
|
72
|
+
| 'success'
|
|
73
|
+
| 'warning'
|
|
74
|
+
| 'primary'
|
|
75
|
+
| 'secondary';
|
|
76
|
+
|
|
68
77
|
export interface MenuItemInterface {
|
|
69
78
|
label?: string;
|
|
70
79
|
href?: string;
|
|
@@ -72,7 +81,7 @@ export interface MenuItemInterface {
|
|
|
72
81
|
action?: () => Promise<void> | void;
|
|
73
82
|
icon?: string;
|
|
74
83
|
count?: number;
|
|
75
|
-
color?:
|
|
84
|
+
color?: ActionColors;
|
|
76
85
|
line?: boolean;
|
|
77
86
|
}
|
|
78
87
|
|
|
@@ -83,7 +92,7 @@ export interface ActionItem {
|
|
|
83
92
|
action?: () => Promise<void> | void;
|
|
84
93
|
icon?: string;
|
|
85
94
|
count?: number;
|
|
86
|
-
color?:
|
|
95
|
+
color?: ActionColors;
|
|
87
96
|
disabled?: boolean;
|
|
88
97
|
meta?: Record<string, any>;
|
|
89
98
|
actions?: ActionItem[];
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t } from '@/i18n';
|
|
2
2
|
|
|
3
3
|
export default function (size: number): string {
|
|
4
4
|
const i = Math.floor(Math.log(size) / Math.log(1024));
|
|
5
5
|
|
|
6
6
|
const units = [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
t('sui.units.b'),
|
|
8
|
+
t('sui.units.kb'),
|
|
9
|
+
t('sui.units.mb'),
|
|
10
|
+
t('sui.units.gb'),
|
|
11
|
+
t('sui.units.tb'),
|
|
12
12
|
];
|
|
13
13
|
|
|
14
14
|
return +(size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + units[i];
|