sprintify-ui 0.1.15 → 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 +11935 -11825
- 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/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 +1 -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/BaseNumber.vue.d.ts +3 -3
- 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/package.json +7 -6
- 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/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/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/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/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/utils/fileSizeFormat.ts +6 -6
- package/src/utils/toHumanList.ts +2 -2
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
:disabled="disabled"
|
|
16
16
|
class="flatpickr w-full rounded pl-10 pr-16 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
17
17
|
:class="[hasErrorInternal ? 'border-red-500' : 'border-slate-300']"
|
|
18
|
-
:placeholder="
|
|
18
|
+
:placeholder="t('sui.click_or_select_date')"
|
|
19
19
|
/>
|
|
20
20
|
<div
|
|
21
21
|
v-if="modelValueFormatted && !disabled"
|
|
@@ -41,9 +41,11 @@ import { useField } from '@/composables/field';
|
|
|
41
41
|
import flatpickr from 'flatpickr';
|
|
42
42
|
import 'flatpickr/dist/flatpickr.css';
|
|
43
43
|
|
|
44
|
+
import { t } from '@/i18n';
|
|
44
45
|
import { French } from 'flatpickr/dist/l10n/fr';
|
|
45
46
|
import { english } from 'flatpickr/dist/l10n/default';
|
|
46
47
|
import { Instance } from 'flatpickr/dist/types/instance';
|
|
48
|
+
import { useI18nStore } from '@/stores/i18n';
|
|
47
49
|
|
|
48
50
|
const props = withDefaults(
|
|
49
51
|
defineProps<{
|
|
@@ -78,8 +80,6 @@ const props = withDefaults(
|
|
|
78
80
|
}
|
|
79
81
|
);
|
|
80
82
|
|
|
81
|
-
const i18n = useI18n();
|
|
82
|
-
|
|
83
83
|
const emit = defineEmits(['update:modelValue']);
|
|
84
84
|
|
|
85
85
|
const formatInternal = computed(() => {
|
|
@@ -140,7 +140,7 @@ function parseDate(date: string): string {
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
const locale = computed(() => {
|
|
143
|
-
if (
|
|
143
|
+
if (useI18nStore().locale == 'fr') {
|
|
144
144
|
return French;
|
|
145
145
|
}
|
|
146
146
|
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
[hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
|
|
16
16
|
]"
|
|
17
|
-
:placeholder="
|
|
17
|
+
:placeholder="t('sui.year')"
|
|
18
18
|
@change="update()"
|
|
19
19
|
>
|
|
20
20
|
<option disabled selected hidden :value="null">
|
|
21
|
-
{{
|
|
21
|
+
{{ t('sui.year') }}
|
|
22
22
|
</option>
|
|
23
23
|
<option v-for="year in years" :key="year" :value="year">
|
|
24
24
|
{{ year }}
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
},
|
|
40
40
|
[hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
|
|
41
41
|
]"
|
|
42
|
-
:placeholder="
|
|
42
|
+
:placeholder="t('sui.month')"
|
|
43
43
|
@change="update()"
|
|
44
44
|
>
|
|
45
45
|
<option disabled selected hidden :value="null">
|
|
46
|
-
{{
|
|
46
|
+
{{ t('sui.month') }}
|
|
47
47
|
</option>
|
|
48
48
|
<option v-for="(month, i) in months" :key="month" :value="i + 1">
|
|
49
49
|
{{ month }}
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
},
|
|
65
65
|
[hasErrorInternal ? 'border-red-500' : 'border-slate-300'],
|
|
66
66
|
]"
|
|
67
|
-
:placeholder="
|
|
67
|
+
:placeholder="t('sui.day')"
|
|
68
68
|
@change="update()"
|
|
69
69
|
>
|
|
70
70
|
<option disabled selected hidden :value="null">
|
|
71
|
-
{{
|
|
71
|
+
{{ t('sui.day') }}
|
|
72
72
|
</option>
|
|
73
73
|
<option v-for="day in days" :key="day" :value="day">
|
|
74
74
|
{{ day }}
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
class="mt-1 appearance-none border-transparent bg-transparent text-sm text-slate-700 underline outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
84
84
|
@click="clear()"
|
|
85
85
|
>
|
|
86
|
-
<span>{{
|
|
86
|
+
<span>{{ t('sui.clear') }}</span>
|
|
87
87
|
</button>
|
|
88
88
|
</div>
|
|
89
89
|
</template>
|
|
@@ -93,6 +93,8 @@ import { PropType } from 'vue';
|
|
|
93
93
|
import { range, padStart } from 'lodash';
|
|
94
94
|
import { DateTime, Info } from 'luxon';
|
|
95
95
|
import { useField } from '@/composables/field';
|
|
96
|
+
import { t } from '@/i18n';
|
|
97
|
+
import { useI18nStore } from '@/stores/i18n';
|
|
96
98
|
|
|
97
99
|
const props = defineProps({
|
|
98
100
|
modelValue: {
|
|
@@ -134,10 +136,8 @@ const { hasErrorInternal, emitUpdate } = useField({
|
|
|
134
136
|
emit: emit,
|
|
135
137
|
});
|
|
136
138
|
|
|
137
|
-
const i18n = useI18n();
|
|
138
|
-
|
|
139
139
|
const years = range(props.maxYear, props.minYear) as number[];
|
|
140
|
-
const months = Info.months('short', { locale:
|
|
140
|
+
const months = Info.months('short', { locale: useI18nStore().locale });
|
|
141
141
|
const days = computed(() => {
|
|
142
142
|
if (!date.value.year) {
|
|
143
143
|
return [];
|
|
@@ -62,14 +62,14 @@
|
|
|
62
62
|
}"
|
|
63
63
|
@click="$emit('confirm')"
|
|
64
64
|
>
|
|
65
|
-
{{ confirmText ??
|
|
65
|
+
{{ confirmText ?? t('sui.confirm') }}
|
|
66
66
|
</button>
|
|
67
67
|
<button
|
|
68
68
|
type="button"
|
|
69
69
|
class="btn w-full sm:mr-2 sm:w-auto"
|
|
70
70
|
@click="$emit('cancel')"
|
|
71
71
|
>
|
|
72
|
-
{{ cancelText ??
|
|
72
|
+
{{ cancelText ?? t('sui.cancel') }}
|
|
73
73
|
</button>
|
|
74
74
|
</div>
|
|
75
75
|
</div>
|
|
@@ -78,6 +78,7 @@
|
|
|
78
78
|
<script lang="ts" setup>
|
|
79
79
|
import { PropType } from 'vue';
|
|
80
80
|
import { Icon as BaseIcon } from '@iconify/vue';
|
|
81
|
+
import { t } from '@/i18n';
|
|
81
82
|
|
|
82
83
|
defineProps({
|
|
83
84
|
color: {
|
|
@@ -94,15 +95,13 @@ defineProps({
|
|
|
94
95
|
},
|
|
95
96
|
confirmText: {
|
|
96
97
|
default() {
|
|
97
|
-
|
|
98
|
-
return i18n.t('sui.confirm');
|
|
98
|
+
return t('sui.confirm');
|
|
99
99
|
},
|
|
100
100
|
type: String,
|
|
101
101
|
},
|
|
102
102
|
cancelText: {
|
|
103
103
|
default() {
|
|
104
|
-
|
|
105
|
-
return i18n.t('sui.cancel');
|
|
104
|
+
return t('sui.cancel');
|
|
106
105
|
},
|
|
107
106
|
type: String,
|
|
108
107
|
},
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
</template>
|
|
16
16
|
|
|
17
17
|
<script lang="ts" setup>
|
|
18
|
+
import { t } from '@/i18n';
|
|
19
|
+
import { useI18nStore } from '@/stores/i18n';
|
|
18
20
|
import humanizeDuration from 'humanize-duration';
|
|
19
21
|
import { DateTime } from 'luxon';
|
|
20
22
|
import { PropType } from 'vue';
|
|
@@ -89,12 +91,10 @@ const intervalId = setInterval(() => {
|
|
|
89
91
|
now.value = DateTime.now().toSeconds();
|
|
90
92
|
}, intervalValue);
|
|
91
93
|
|
|
92
|
-
const i18n = useI18n();
|
|
93
|
-
|
|
94
94
|
const readableDate = computed(() => {
|
|
95
95
|
const duration = getDuration();
|
|
96
96
|
const durationHuman = humanizeDuration(duration, {
|
|
97
|
-
language:
|
|
97
|
+
language: useI18nStore().locale,
|
|
98
98
|
round: true,
|
|
99
99
|
largest: 1,
|
|
100
100
|
});
|
|
@@ -102,15 +102,15 @@ const readableDate = computed(() => {
|
|
|
102
102
|
const minutes = getMinutes(duration);
|
|
103
103
|
|
|
104
104
|
if (minutes < 1) {
|
|
105
|
-
return
|
|
105
|
+
return t('sui.just_now');
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
return
|
|
108
|
+
return t('sui.x_ago', { duration: durationHuman });
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
const tooltip = computed(() => {
|
|
112
112
|
return DateTime.fromISO(props.value)
|
|
113
|
-
.setLocale(
|
|
113
|
+
.setLocale(useI18nStore().locale)
|
|
114
114
|
.toLocaleString(DateTime.DATETIME_FULL);
|
|
115
115
|
});
|
|
116
116
|
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
</template>
|
|
25
25
|
|
|
26
26
|
<script lang="ts" setup>
|
|
27
|
+
import { t } from '@/i18n';
|
|
27
28
|
import { useNotificationsStore } from '@/stores/notifications';
|
|
28
29
|
import { fileSizeFormat, toHumanList } from '@/utils';
|
|
29
30
|
import { maxSize, validExtension } from '@/utils/fileValidations';
|
|
@@ -49,8 +50,6 @@ const emit = defineEmits(['select']);
|
|
|
49
50
|
|
|
50
51
|
const notifications = useNotificationsStore();
|
|
51
52
|
|
|
52
|
-
const i18n = useI18n();
|
|
53
|
-
|
|
54
53
|
const selecting = ref(false);
|
|
55
54
|
const dragging = ref(false);
|
|
56
55
|
const input = ref<HTMLInputElement | undefined>();
|
|
@@ -95,8 +94,8 @@ async function select(files: File[]) {
|
|
|
95
94
|
if (!maxSize(file, props.maxSize)) {
|
|
96
95
|
notifications.push({
|
|
97
96
|
color: 'danger',
|
|
98
|
-
title:
|
|
99
|
-
text:
|
|
97
|
+
title: t('sui.error'),
|
|
98
|
+
text: t('sui.the_file_size_must_not_exceed_x', {
|
|
100
99
|
x: fileSizeFormat(props.maxSize),
|
|
101
100
|
}),
|
|
102
101
|
});
|
|
@@ -108,13 +107,13 @@ async function select(files: File[]) {
|
|
|
108
107
|
if (!validExtension(file, props.acceptedExtensions)) {
|
|
109
108
|
notifications.push({
|
|
110
109
|
color: 'danger',
|
|
111
|
-
title:
|
|
110
|
+
title: t('sui.error'),
|
|
112
111
|
text:
|
|
113
|
-
|
|
112
|
+
t('sui.the_file_type_is_invalid') +
|
|
114
113
|
' ' +
|
|
115
|
-
|
|
114
|
+
t('sui.file_must_be_of_type') +
|
|
116
115
|
' ' +
|
|
117
|
-
toHumanList(props.acceptedExtensions as string[],
|
|
116
|
+
toHumanList(props.acceptedExtensions as string[], t('sui.or')) +
|
|
118
117
|
'.',
|
|
119
118
|
});
|
|
120
119
|
|
|
@@ -37,9 +37,9 @@ import BaseLoadingCover from '@/components/BaseLoadingCover.vue';
|
|
|
37
37
|
import { BaseCropperConfig } from '@/types';
|
|
38
38
|
import BaseFilePicker from './BaseFilePicker.vue';
|
|
39
39
|
import BaseFilePickerCrop from './BaseFilePickerCrop.vue';
|
|
40
|
+
import { t } from '@/i18n';
|
|
40
41
|
|
|
41
42
|
const http = config.http;
|
|
42
|
-
const i18n = useI18n();
|
|
43
43
|
const notifications = useNotificationsStore();
|
|
44
44
|
|
|
45
45
|
const props = withDefaults(
|
|
@@ -148,8 +148,8 @@ async function onFileSelect(file: File) {
|
|
|
148
148
|
emit('upload:fail');
|
|
149
149
|
notifications.push({
|
|
150
150
|
color: 'danger',
|
|
151
|
-
title:
|
|
152
|
-
text:
|
|
151
|
+
title: t('sui.error'),
|
|
152
|
+
text: t('sui.upload_failed'),
|
|
153
153
|
});
|
|
154
154
|
} finally {
|
|
155
155
|
emit('upload:end');
|
|
@@ -45,6 +45,7 @@ import { Method, DataFormat } from '@/types';
|
|
|
45
45
|
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
|
46
46
|
import { config, useNotificationsStore } from '@/index';
|
|
47
47
|
import { get, isArray } from 'lodash';
|
|
48
|
+
import { t } from '@/i18n';
|
|
48
49
|
|
|
49
50
|
const notifications = useNotificationsStore();
|
|
50
51
|
|
|
@@ -107,7 +108,6 @@ const props = defineProps({
|
|
|
107
108
|
},
|
|
108
109
|
});
|
|
109
110
|
|
|
110
|
-
const i18n = useI18n();
|
|
111
111
|
const emit = defineEmits(['error', 'success']);
|
|
112
112
|
|
|
113
113
|
const form = ref<null | HTMLFormElement>(null);
|
|
@@ -226,7 +226,7 @@ function query() {
|
|
|
226
226
|
if (props.showNotificationOnError && errorMessage) {
|
|
227
227
|
notifications.push({
|
|
228
228
|
color: 'danger',
|
|
229
|
-
title:
|
|
229
|
+
title: t('sui.error'),
|
|
230
230
|
text: errorMessage,
|
|
231
231
|
});
|
|
232
232
|
}
|
|
@@ -248,7 +248,7 @@ function successHandler(response: AxiosResponse<any, any>) {
|
|
|
248
248
|
if (props.showNotificationOnSuccess) {
|
|
249
249
|
notifications.push({
|
|
250
250
|
color: 'success',
|
|
251
|
-
title:
|
|
251
|
+
title: t('sui.success'),
|
|
252
252
|
text: message,
|
|
253
253
|
});
|
|
254
254
|
}
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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
|
|