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
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
v-model="searchQuery"
|
|
29
29
|
type="text"
|
|
30
30
|
class="h-11 w-full overflow-hidden rounded-md border border-slate-300 bg-white pl-10 pr-9 shadow-sm"
|
|
31
|
-
:placeholder="
|
|
31
|
+
:placeholder="t('sui.autocomplete_placeholder')"
|
|
32
32
|
@input="onSearch"
|
|
33
33
|
/>
|
|
34
34
|
<div
|
|
@@ -102,11 +102,11 @@
|
|
|
102
102
|
<p
|
|
103
103
|
class="text-center text-sm text-slate-500 sm:text-right [&>b]:font-medium [&>b]:text-slate-600"
|
|
104
104
|
>
|
|
105
|
-
{{
|
|
105
|
+
{{ t('sui.pagination_detail_1') }}
|
|
106
106
|
|
|
107
107
|
<b>{{ paginationStart }}</b> - <b>{{ paginationEnd }}</b>
|
|
108
108
|
|
|
109
|
-
{{
|
|
109
|
+
{{ t('sui.pagination_detail_2') }}
|
|
110
110
|
|
|
111
111
|
<b>{{ paginationMetadata.total }}</b>
|
|
112
112
|
</p>
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
|
|
165
165
|
<script lang="ts">
|
|
166
166
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
167
|
-
|
|
167
|
+
import { t } from '@/i18n';
|
|
168
168
|
type Direction = 'asc' | 'desc';
|
|
169
169
|
|
|
170
170
|
const DEFAULT_QUERY = {
|
|
@@ -276,7 +276,6 @@ const props = defineProps({
|
|
|
276
276
|
},
|
|
277
277
|
});
|
|
278
278
|
|
|
279
|
-
const i18n = useI18n();
|
|
280
279
|
const http = config.http;
|
|
281
280
|
|
|
282
281
|
const emit = defineEmits([
|
|
@@ -730,8 +729,8 @@ const sectionsInternal = computed<DataIteratorSection[]>(() => {
|
|
|
730
729
|
return [
|
|
731
730
|
{
|
|
732
731
|
name: 'filters',
|
|
733
|
-
title:
|
|
734
|
-
closeText:
|
|
732
|
+
title: t('sui.filters'),
|
|
733
|
+
closeText: t('sui.apply_filters'),
|
|
735
734
|
icon: 'heroicons:adjustments-horizontal-solid',
|
|
736
735
|
opened: true,
|
|
737
736
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<div>
|
|
33
33
|
<span class="mr-3 text-slate-500"
|
|
34
34
|
>{{
|
|
35
|
-
|
|
35
|
+
t('sui.x_rows_selected', {
|
|
36
36
|
count: newCheckedRows.length,
|
|
37
37
|
})
|
|
38
38
|
}}.</span
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
class="mr-3 inline text-slate-700 underline"
|
|
43
43
|
@click="uncheckAll()"
|
|
44
44
|
>
|
|
45
|
-
{{
|
|
45
|
+
{{ t('sui.deselect_all') }}
|
|
46
46
|
</button>
|
|
47
47
|
</div>
|
|
48
48
|
<BaseMenu
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
class="h-10 w-10 text-red-600"
|
|
136
136
|
/>
|
|
137
137
|
<p class="mt-3 text-center text-sm text-slate-600">
|
|
138
|
-
{{
|
|
138
|
+
{{ t('sui.whoops') }}
|
|
139
139
|
</p>
|
|
140
140
|
</div>
|
|
141
141
|
</div>
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
<BaseEmptyState class="w-32"></BaseEmptyState>
|
|
148
148
|
|
|
149
149
|
<p class="mt-3 text-center text-sm text-slate-600">
|
|
150
|
-
{{
|
|
150
|
+
{{ t('sui.nothing_found') }}
|
|
151
151
|
</p>
|
|
152
152
|
</div>
|
|
153
153
|
</div>
|
|
@@ -192,6 +192,7 @@
|
|
|
192
192
|
|
|
193
193
|
<script lang="ts" setup>
|
|
194
194
|
import { PropType } from 'vue';
|
|
195
|
+
import { t } from '@/i18n';
|
|
195
196
|
import {
|
|
196
197
|
Collection,
|
|
197
198
|
CollectionItem,
|
|
@@ -217,7 +218,6 @@ import { RouteLocationRaw } from 'vue-router';
|
|
|
217
218
|
import BaseMenu from './BaseMenu.vue';
|
|
218
219
|
import BaseDataTableRowAction from './BaseDataTableRowAction.vue';
|
|
219
220
|
|
|
220
|
-
const i18n = useI18n();
|
|
221
221
|
const router = useRouter();
|
|
222
222
|
|
|
223
223
|
const http = config.http;
|
|
@@ -468,11 +468,11 @@ const canDelete = (row: CollectionItem): boolean => {
|
|
|
468
468
|
|
|
469
469
|
function onDeleteClick(row: CollectionItem) {
|
|
470
470
|
dialogs.push({
|
|
471
|
-
title:
|
|
472
|
-
message:
|
|
471
|
+
title: t('sui.delete_record') + '?',
|
|
472
|
+
message: t('sui.delete_record_description'),
|
|
473
473
|
color: 'danger',
|
|
474
474
|
closeOnOutsideClick: true,
|
|
475
|
-
confirmText:
|
|
475
|
+
confirmText: t('sui.yes_delete'),
|
|
476
476
|
onConfirm: () => onDelete(row),
|
|
477
477
|
});
|
|
478
478
|
}
|
|
@@ -487,7 +487,7 @@ const onDelete = (row: CollectionItem) => {
|
|
|
487
487
|
.then((response) => {
|
|
488
488
|
if (response.data && response.data.message) {
|
|
489
489
|
notifications.push({
|
|
490
|
-
title:
|
|
490
|
+
title: t('sui.success'),
|
|
491
491
|
text: response.data.message,
|
|
492
492
|
color: 'success',
|
|
493
493
|
});
|
|
@@ -499,7 +499,7 @@ const onDelete = (row: CollectionItem) => {
|
|
|
499
499
|
})
|
|
500
500
|
.catch((error) => {
|
|
501
501
|
notifications.push({
|
|
502
|
-
title:
|
|
502
|
+
title: t('sui.error'),
|
|
503
503
|
text: error.response.data?.message ?? 'Unknown error',
|
|
504
504
|
color: 'danger',
|
|
505
505
|
});
|
|
@@ -572,7 +572,7 @@ const rowActionsInternal = computed<RowAction[]>(() => {
|
|
|
572
572
|
|
|
573
573
|
if (props.editUrl && props.editButton) {
|
|
574
574
|
actions.push({
|
|
575
|
-
label:
|
|
575
|
+
label: t('sui.edit'),
|
|
576
576
|
icon: 'heroicons:cog-6-tooth-solid',
|
|
577
577
|
to: (row: CollectionItem) => (props.editUrl ? props.editUrl(row) : ''),
|
|
578
578
|
disabled: (row: CollectionItem) => !canUpdate(row),
|
|
@@ -581,7 +581,7 @@ const rowActionsInternal = computed<RowAction[]>(() => {
|
|
|
581
581
|
|
|
582
582
|
if (props.deleteUrl && props.deleteButton) {
|
|
583
583
|
actions.push({
|
|
584
|
-
label:
|
|
584
|
+
label: t('sui.delete'),
|
|
585
585
|
icon: 'heroicons:trash-20-solid',
|
|
586
586
|
action: onDeleteClick,
|
|
587
587
|
disabled: (row: CollectionItem) => !canDelete(row),
|
|
@@ -643,8 +643,8 @@ const sectionsInternal = computed<DataIteratorSection[]>(() => {
|
|
|
643
643
|
{
|
|
644
644
|
name: 'columns',
|
|
645
645
|
icon: 'heroicons:table-cells-20-solid',
|
|
646
|
-
title:
|
|
647
|
-
closeText:
|
|
646
|
+
title: t('sui.columns'),
|
|
647
|
+
closeText: t('sui.apply'),
|
|
648
648
|
opened: false,
|
|
649
649
|
},
|
|
650
650
|
];
|
|
@@ -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
|
}
|
|
@@ -35,11 +35,6 @@ const attributes = [
|
|
|
35
35
|
];
|
|
36
36
|
|
|
37
37
|
const actions = [
|
|
38
|
-
{
|
|
39
|
-
label: 'Edit',
|
|
40
|
-
to: '/articles',
|
|
41
|
-
icon: 'heroicons:pencil-solid',
|
|
42
|
-
},
|
|
43
38
|
{
|
|
44
39
|
label: 'View',
|
|
45
40
|
icon: 'heroicons:link-solid',
|
|
@@ -47,6 +42,18 @@ const actions = [
|
|
|
47
42
|
alert('View');
|
|
48
43
|
},
|
|
49
44
|
},
|
|
45
|
+
{
|
|
46
|
+
label: 'Edit',
|
|
47
|
+
to: '/articles',
|
|
48
|
+
icon: 'heroicons:pencil-solid',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: 'Publish 2',
|
|
52
|
+
to: '/articles',
|
|
53
|
+
color: 'secondary',
|
|
54
|
+
icon: 'heroicons:check-solid',
|
|
55
|
+
},
|
|
56
|
+
|
|
50
57
|
{
|
|
51
58
|
label: 'Publish',
|
|
52
59
|
to: '/articles',
|
|
@@ -61,46 +61,38 @@
|
|
|
61
61
|
</div>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
|
-
<div
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
<BaseMenu
|
|
72
|
-
v-if="secondaryActions.length > 1"
|
|
73
|
-
:items="secondaryActions"
|
|
74
|
-
size="sm"
|
|
75
|
-
position="bottom-right"
|
|
64
|
+
<div class="mt-5">
|
|
65
|
+
<div
|
|
66
|
+
class="flex gap-2"
|
|
67
|
+
:class="{
|
|
68
|
+
'lg:mt-0 lg:ml-4': !compactLayout,
|
|
69
|
+
}"
|
|
76
70
|
>
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
size="sm"
|
|
103
|
-
/>
|
|
71
|
+
<BaseActionItemButton
|
|
72
|
+
v-for="(primaryAction, i) in primaryActions"
|
|
73
|
+
:key="i"
|
|
74
|
+
:action="primaryAction"
|
|
75
|
+
size="sm"
|
|
76
|
+
/>
|
|
77
|
+
<BaseMenu
|
|
78
|
+
v-if="secondaryActions.length"
|
|
79
|
+
:items="secondaryActions"
|
|
80
|
+
size="sm"
|
|
81
|
+
:position="compactLayout ? 'bottom-right' : 'bottom-left'"
|
|
82
|
+
>
|
|
83
|
+
<template #button="{ open }">
|
|
84
|
+
<div
|
|
85
|
+
class="btn btn-sm flex items-center rounded-full p-2 hover:border-slate-400"
|
|
86
|
+
:class="[open ? 'bg-slate-100' : '']"
|
|
87
|
+
>
|
|
88
|
+
<BaseIcon
|
|
89
|
+
icon="heroicons-outline:dots-horizontal"
|
|
90
|
+
class="h-4 w-4 text-slate-500"
|
|
91
|
+
/>
|
|
92
|
+
</div>
|
|
93
|
+
</template>
|
|
94
|
+
</BaseMenu>
|
|
95
|
+
</div>
|
|
104
96
|
</div>
|
|
105
97
|
</div>
|
|
106
98
|
</div>
|
|
@@ -113,6 +105,7 @@ import { BaseBreadcrumbs, BaseIcon } from '..';
|
|
|
113
105
|
import BaseActionItemButton from './BaseActionItemButton.vue';
|
|
114
106
|
import BaseBadge from './BaseBadge.vue';
|
|
115
107
|
import BaseMenu from './BaseMenu.vue';
|
|
108
|
+
import { cloneDeep } from 'lodash';
|
|
116
109
|
|
|
117
110
|
const props = withDefaults(
|
|
118
111
|
defineProps<{
|
|
@@ -123,6 +116,7 @@ const props = withDefaults(
|
|
|
123
116
|
badge?: { icon: string; label: string; color: string };
|
|
124
117
|
layout?: 'default' | 'compact';
|
|
125
118
|
breadcrumbs?: Breadcrumb[];
|
|
119
|
+
maxActions?: number;
|
|
126
120
|
}>(),
|
|
127
121
|
{
|
|
128
122
|
subtitle: undefined,
|
|
@@ -131,59 +125,64 @@ const props = withDefaults(
|
|
|
131
125
|
badge: undefined,
|
|
132
126
|
layout: 'default',
|
|
133
127
|
breadcrumbs: undefined,
|
|
128
|
+
maxActions: 3,
|
|
134
129
|
}
|
|
135
130
|
);
|
|
136
131
|
|
|
137
|
-
const
|
|
138
|
-
if (!props.actions || props.actions.length === 0) {
|
|
139
|
-
return undefined;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (props.actions?.length === 1) {
|
|
143
|
-
return 0;
|
|
144
|
-
}
|
|
132
|
+
const baseHeaderRef = ref<HTMLElement | null>(null);
|
|
145
133
|
|
|
146
|
-
|
|
134
|
+
const width = ref(800);
|
|
135
|
+
useResizeObserver(baseHeaderRef, () => {
|
|
136
|
+
width.value = baseHeaderRef.value?.clientWidth ?? 800;
|
|
137
|
+
});
|
|
147
138
|
|
|
148
|
-
|
|
149
|
-
|
|
139
|
+
const compactLayout = computed(() => {
|
|
140
|
+
if (props.layout === 'compact') {
|
|
141
|
+
return true;
|
|
150
142
|
}
|
|
151
|
-
|
|
152
|
-
return 0;
|
|
143
|
+
return width.value < 500;
|
|
153
144
|
});
|
|
154
145
|
|
|
155
|
-
const
|
|
156
|
-
if (
|
|
157
|
-
return
|
|
146
|
+
const maxActionsInternal = computed(() => {
|
|
147
|
+
if (compactLayout.value) {
|
|
148
|
+
return 1;
|
|
158
149
|
}
|
|
150
|
+
return Math.max(1, props.maxActions);
|
|
151
|
+
});
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return props.actions[index];
|
|
153
|
+
const primaryActions = computed(() => {
|
|
154
|
+
if (!props.actions) {
|
|
155
|
+
return [];
|
|
164
156
|
}
|
|
165
157
|
|
|
166
|
-
return
|
|
158
|
+
return cloneDeep(props.actions)
|
|
159
|
+
.sort(sortByColor(false))
|
|
160
|
+
.slice(0, maxActionsInternal.value)
|
|
161
|
+
.sort(sortByColor(true));
|
|
167
162
|
});
|
|
168
163
|
|
|
164
|
+
function sortByColor(reverse = false) {
|
|
165
|
+
const sortingArr = ['secondary', 'primary'];
|
|
166
|
+
|
|
167
|
+
return (a: ActionItem, b: ActionItem) => {
|
|
168
|
+
if (!reverse) {
|
|
169
|
+
return (
|
|
170
|
+
sortingArr.indexOf(b.color ?? '') - sortingArr.indexOf(a.color ?? '')
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
return (
|
|
174
|
+
sortingArr.indexOf(a.color ?? '') - sortingArr.indexOf(b.color ?? '')
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
const secondaryActions = computed(() => {
|
|
170
180
|
if (!props.actions) {
|
|
171
181
|
return [];
|
|
172
182
|
}
|
|
173
|
-
return props.actions?.filter((a, i) => i !== primaryActionIndex.value);
|
|
174
|
-
});
|
|
175
183
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
useResizeObserver(baseHeaderRef, () => {
|
|
180
|
-
width.value = baseHeaderRef.value?.clientWidth ?? 800;
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
const compactLayout = computed(() => {
|
|
184
|
-
if (props.layout === 'compact') {
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
return width.value < 500;
|
|
184
|
+
return props.actions.filter(
|
|
185
|
+
(a) => !primaryActions.value.map((a) => a.label).includes(a.label)
|
|
186
|
+
);
|
|
188
187
|
});
|
|
189
188
|
</script>
|