@bagelink/vue 1.9.49 → 1.9.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AddressSearch.vue.d.ts.map +1 -1
- package/dist/components/Btn.vue.d.ts +2 -2
- package/dist/components/Btn.vue.d.ts.map +1 -1
- package/dist/components/Filter.vue.d.ts +0 -1
- package/dist/components/Filter.vue.d.ts.map +1 -1
- package/dist/components/ImportData.vue.d.ts.map +1 -1
- package/dist/components/ModalConfirm.vue.d.ts.map +1 -1
- package/dist/components/Spreadsheet/Index.vue.d.ts.map +1 -1
- package/dist/components/form/FieldArray.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/ColorInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts +1 -1
- package/dist/components/form/inputs/DateInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts +1 -1
- package/dist/components/form/inputs/DatePicker.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/EmailInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts +1 -1
- package/dist/components/form/inputs/PasswordInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/RadioPillsInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts +0 -1
- package/dist/components/form/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/TelInput.vue.d.ts.map +1 -1
- package/dist/components/form/inputs/Upload/UploadInput.vue.d.ts.map +1 -1
- package/dist/components/lightbox/Lightbox.vue.d.ts.map +1 -1
- package/dist/dialog/DialogConfirm.vue.d.ts +0 -3
- package/dist/dialog/DialogConfirm.vue.d.ts.map +1 -1
- package/dist/dialog/DialogForm.vue.d.ts.map +1 -1
- package/dist/form-flow/FormFlow.vue.d.ts.map +1 -1
- package/dist/form-flow/MultiStepForm.vue.d.ts.map +1 -1
- package/dist/i18n/index.d.ts +996 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/index.cjs +135 -130
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +15415 -11483
- package/dist/plugins/bagel.d.ts +5 -7
- package/dist/plugins/bagel.d.ts.map +1 -1
- package/dist/plugins/useToast.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +4 -3
- package/dist/utils/calendar/dateUtils.d.ts.map +1 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/lang.d.ts +6 -7
- package/dist/utils/lang.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/AddressSearch.vue +5 -2
- package/src/components/Btn.vue +8 -6
- package/src/components/Filter.vue +37 -76
- package/src/components/ImportData.vue +35 -29
- package/src/components/ModalConfirm.vue +9 -7
- package/src/components/Spreadsheet/Index.vue +35 -60
- package/src/components/form/FieldArray.vue +4 -2
- package/src/components/form/inputs/ColorInput.vue +18 -12
- package/src/components/form/inputs/DateInput.vue +7 -4
- package/src/components/form/inputs/EmailInput.vue +9 -7
- package/src/components/form/inputs/PasswordInput.vue +17 -15
- package/src/components/form/inputs/RadioPillsInput.vue +5 -3
- package/src/components/form/inputs/SelectInput.vue +13 -11
- package/src/components/form/inputs/TelInput.vue +11 -9
- package/src/components/form/inputs/Upload/UploadInput.vue +7 -5
- package/src/components/lightbox/Lightbox.vue +4 -1
- package/src/dialog/DialogConfirm.vue +11 -6
- package/src/dialog/DialogForm.vue +9 -9
- package/src/form-flow/FormFlow.vue +7 -15
- package/src/form-flow/MultiStepForm.vue +16 -12
- package/src/i18n/index.ts +130 -0
- package/src/i18n/locales/en.json +153 -0
- package/src/i18n/locales/es.json +153 -0
- package/src/i18n/locales/fr.json +153 -0
- package/src/i18n/locales/he.json +174 -0
- package/src/i18n/locales/it.json +153 -0
- package/src/i18n/locales/ru.json +153 -0
- package/src/index.ts +11 -5
- package/src/plugins/bagel.ts +14 -26
- package/src/plugins/useToast.ts +4 -2
- package/src/styles/text.css +2 -1
- package/src/utils/calendar/dateUtils.ts +91 -59
- package/src/utils/index.ts +0 -2
- package/src/utils/lang.ts +0 -46
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { Btn, CheckInput, TextInput, ToggleInput, localRef, ListItem, Dropdown } from '@bagelink/vue'
|
|
2
|
+
import { Btn, CheckInput, TextInput, ToggleInput, localRef, ListItem, Dropdown, useI18n } from '@bagelink/vue'
|
|
3
3
|
import { computed, ref, watch, nextTick, onUnmounted } from 'vue'
|
|
4
4
|
import SpreadsheetTable from './SpreadsheetTable.vue'
|
|
5
5
|
|
|
6
|
+
const { modelValue, columnConfig, label, allowAddRow = true } = defineProps<Props>()
|
|
7
|
+
|
|
8
|
+
const emit = defineEmits(['update:modelValue'])
|
|
9
|
+
|
|
10
|
+
const { $t } = useI18n()
|
|
11
|
+
|
|
6
12
|
// Define column configuration types
|
|
7
13
|
type ColumnFormat = 'text' | 'number' | 'currency' | 'date' | 'percentage' | 'image' | 'boolean'
|
|
8
14
|
|
|
@@ -26,9 +32,6 @@ interface Props {
|
|
|
26
32
|
allowAddRow?: boolean
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
const { modelValue, columnConfig, label, allowAddRow = true } = defineProps<Props>()
|
|
30
|
-
const emit = defineEmits(['update:modelValue'])
|
|
31
|
-
|
|
32
35
|
// Helper function to flatten an object with dot notation
|
|
33
36
|
function flattenObject(obj: { [key: string]: any }, prefix = ''): { [key: string]: any } {
|
|
34
37
|
const flattened: { [key: string]: any } = {}
|
|
@@ -692,29 +695,31 @@ const columnOptions = computed(() => {
|
|
|
692
695
|
<div class="flex gap-05 py-05 justify-content-end m_flex-wrap">
|
|
693
696
|
<label v-if="label" class="label me-auto">{{ label }}</label>
|
|
694
697
|
<div class="flex gap-075">
|
|
695
|
-
<TextInput
|
|
698
|
+
<TextInput
|
|
699
|
+
ref="searchInputRef" v-model="search" icon="search" placeholder="Search"
|
|
700
|
+
class="m-0 max-w200px"
|
|
701
|
+
/>
|
|
696
702
|
<Dropdown flat thin icon="more_vert">
|
|
697
703
|
<ListItem title="Paste" icon="paste" @click="pasteSelection" />
|
|
698
704
|
<ListItem title="copy" icon="copy" @click="copySelection" />
|
|
699
705
|
<ListItem title="Undo" icon="undo" :disabled="!canUndo" @click="undo" />
|
|
700
706
|
<ListItem title="Redo" icon="redo" :disabled="!canRedo" @click="redo" />
|
|
701
|
-
<ToggleInput v-model="wrapText" label="
|
|
707
|
+
<ToggleInput v-model="wrapText" :label="$t('spreadsheet.wrapText')" />
|
|
702
708
|
<Dropdown placement="auto-end">
|
|
703
709
|
<template #trigger="{ show }">
|
|
704
710
|
<ListItem title="Column Visibility" icon="view_column" @click="show()" />
|
|
705
711
|
</template>
|
|
706
712
|
<div class="p-05">
|
|
707
713
|
<div class="flex space-between">
|
|
708
|
-
<Btn
|
|
709
|
-
|
|
714
|
+
<Btn
|
|
715
|
+
flat thin small value="$t:spreadsheet.selectAll"
|
|
716
|
+
@click="visibleColumns = columnOptions.map(col => col.key)"
|
|
717
|
+
/>
|
|
718
|
+
<Btn flat thin small value="$t:spreadsheet.clearAll" @click="visibleColumns = []" />
|
|
710
719
|
</div>
|
|
711
720
|
<CheckInput
|
|
712
|
-
v-for="col in columnOptions"
|
|
713
|
-
:key="col.key"
|
|
714
|
-
v-model="visibleColumns"
|
|
715
|
-
:value="col.key"
|
|
716
|
-
:label="col.label || col.key"
|
|
717
|
-
@update:modelValue="val => undefined"
|
|
721
|
+
v-for="col in columnOptions" :key="col.key" v-model="visibleColumns"
|
|
722
|
+
:value="col.key" :label="col.label || col.key" @update:modelValue="val => undefined"
|
|
718
723
|
/>
|
|
719
724
|
</div>
|
|
720
725
|
</Dropdown>
|
|
@@ -725,57 +730,27 @@ const columnOptions = computed(() => {
|
|
|
725
730
|
<div class="flex w-100p relative">
|
|
726
731
|
<!-- Fixed Columns -->
|
|
727
732
|
<SpreadsheetTable
|
|
728
|
-
v-if="fixedColumns.length"
|
|
729
|
-
:
|
|
730
|
-
:
|
|
731
|
-
:
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
:selection-start="selectionStart"
|
|
737
|
-
:selection-end="selectionEnd"
|
|
738
|
-
:editing-cell="editingCell"
|
|
739
|
-
:base-column-index="0"
|
|
740
|
-
:wrap-text="wrapText"
|
|
741
|
-
class="sticky z-2 start-0 bg-white"
|
|
742
|
-
@sortColumn="sortByColumn"
|
|
743
|
-
@resizeStart="handleResizeStart"
|
|
744
|
-
@selectRow="selectEntireRow"
|
|
745
|
-
@cellMouseDown="handleMouseDown"
|
|
746
|
-
@cellMouseOver="handleMouseOver"
|
|
747
|
-
@cellEditStart="startEditing"
|
|
748
|
-
@cellKeyDown="handleCellKeyDown"
|
|
749
|
-
@updateCell="updateCell"
|
|
750
|
-
@stopEditing="handleStopEditingAndBlur"
|
|
751
|
-
@setInputRef="setInputRef"
|
|
733
|
+
v-if="fixedColumns.length" :columns="fixedColumns" :rows="filteredRows"
|
|
734
|
+
:is-fixed="true" :show-row-numbers="true" :column-widths="columnWidths" :sort-column="sortColumn"
|
|
735
|
+
:sort-direction="sortDirection" :selection-start="selectionStart" :selection-end="selectionEnd"
|
|
736
|
+
:editing-cell="editingCell" :base-column-index="0" :wrap-text="wrapText"
|
|
737
|
+
class="sticky z-2 start-0 bg-white" @sortColumn="sortByColumn" @resizeStart="handleResizeStart"
|
|
738
|
+
@selectRow="selectEntireRow" @cellMouseDown="handleMouseDown" @cellMouseOver="handleMouseOver"
|
|
739
|
+
@cellEditStart="startEditing" @cellKeyDown="handleCellKeyDown" @updateCell="updateCell"
|
|
740
|
+
@stopEditing="handleStopEditingAndBlur" @setInputRef="setInputRef"
|
|
752
741
|
/>
|
|
753
742
|
|
|
754
743
|
<!-- Scrollable Columns -->
|
|
755
744
|
<div class="flex-shrink flex-grow">
|
|
756
745
|
<SpreadsheetTable
|
|
757
|
-
:columns="scrollableColumns"
|
|
758
|
-
:
|
|
759
|
-
:
|
|
760
|
-
:
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
:selection-end="selectionEnd"
|
|
766
|
-
:editing-cell="editingCell"
|
|
767
|
-
:base-column-index="fixedColumns.length"
|
|
768
|
-
:wrap-text="wrapText"
|
|
769
|
-
@sortColumn="sortByColumn"
|
|
770
|
-
@resizeStart="handleResizeStart"
|
|
771
|
-
@selectRow="selectEntireRow"
|
|
772
|
-
@cellMouseDown="handleMouseDown"
|
|
773
|
-
@cellMouseOver="handleMouseOver"
|
|
774
|
-
@cellEditStart="startEditing"
|
|
775
|
-
@cellKeyDown="handleCellKeyDown"
|
|
776
|
-
@updateCell="updateCell"
|
|
777
|
-
@stopEditing="handleStopEditingAndBlur"
|
|
778
|
-
@setInputRef="setInputRef"
|
|
746
|
+
:columns="scrollableColumns" :rows="filteredRows" :is-fixed="false"
|
|
747
|
+
:show-row-numbers="!fixedColumns.length" :column-widths="columnWidths" :sort-column="sortColumn"
|
|
748
|
+
:sort-direction="sortDirection" :selection-start="selectionStart" :selection-end="selectionEnd"
|
|
749
|
+
:editing-cell="editingCell" :base-column-index="fixedColumns.length" :wrap-text="wrapText"
|
|
750
|
+
@sortColumn="sortByColumn" @resizeStart="handleResizeStart" @selectRow="selectEntireRow"
|
|
751
|
+
@cellMouseDown="handleMouseDown" @cellMouseOver="handleMouseOver" @cellEditStart="startEditing"
|
|
752
|
+
@cellKeyDown="handleCellKeyDown" @updateCell="updateCell"
|
|
753
|
+
@stopEditing="handleStopEditingAndBlur" @setInputRef="setInputRef"
|
|
779
754
|
/>
|
|
780
755
|
</div>
|
|
781
756
|
</div>
|
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
Path
|
|
11
11
|
} from '@bagelink/vue'
|
|
12
12
|
import type { MaybeRefOrGetter } from 'vue'
|
|
13
|
-
import { BagelForm, Btn, Loading, Icon, Card } from '@bagelink/vue'
|
|
13
|
+
import { BagelForm, Btn, Loading, Icon, Card, useI18n } from '@bagelink/vue'
|
|
14
14
|
import { ref, computed, watch, toValue, onMounted } from 'vue'
|
|
15
15
|
|
|
16
16
|
export interface FieldArrayProps<T, P extends Path<T>> {
|
|
@@ -52,6 +52,8 @@ const props = withDefaults(
|
|
|
52
52
|
|
|
53
53
|
const emit = defineEmits(['update:modelValue'])
|
|
54
54
|
|
|
55
|
+
const { $t } = useI18n()
|
|
56
|
+
|
|
55
57
|
const BagelFormFA = BagelForm<T, P>
|
|
56
58
|
|
|
57
59
|
// State
|
|
@@ -297,7 +299,7 @@ const showMinimizeButton = computed(() => {
|
|
|
297
299
|
v-if="props.defaultValue && props.defaultValue.length > 0" thin color="primary"
|
|
298
300
|
class="txt12 mb-05" @click="loadDefaults"
|
|
299
301
|
>
|
|
300
|
-
|
|
302
|
+
{{ $t('fieldArray.loadDefault', { label: label || 'Items' }) }}
|
|
301
303
|
</Btn>
|
|
302
304
|
</Card>
|
|
303
305
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { Btn } from '@bagelink/vue'
|
|
2
|
+
import { Btn, useI18n } from '@bagelink/vue'
|
|
3
3
|
import { ref, watch } from 'vue'
|
|
4
4
|
|
|
5
5
|
const props = withDefaults(
|
|
@@ -17,7 +17,11 @@ const props = withDefaults(
|
|
|
17
17
|
editMode: true,
|
|
18
18
|
},
|
|
19
19
|
)
|
|
20
|
+
|
|
20
21
|
const emits = defineEmits(['update:modelValue'])
|
|
22
|
+
|
|
23
|
+
const { $t } = useI18n()
|
|
24
|
+
|
|
21
25
|
const inputVal = ref<string>(props.modelValue)
|
|
22
26
|
|
|
23
27
|
watch(
|
|
@@ -32,34 +36,36 @@ watch(
|
|
|
32
36
|
{{ label }}
|
|
33
37
|
<div class="flex rounded colorInputPickWrap" :class="{ 'px-025 bg-input': !small }">
|
|
34
38
|
<input
|
|
35
|
-
:id="id"
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
:id="id" v-model="inputVal" class="border" type="color" :placeholder="placeholder || label"
|
|
40
|
+
:class="{ 'no-edit': !editMode, 'opacity-1': !inputVal }" :required="required"
|
|
41
|
+
v-bind="nativeInputAttrs"
|
|
38
42
|
>
|
|
39
43
|
<input
|
|
40
|
-
v-if="!small"
|
|
41
|
-
|
|
42
|
-
class="flex-grow-1 border colorInputPick"
|
|
43
|
-
type="text"
|
|
44
|
-
placeholder="Enter color"
|
|
44
|
+
v-if="!small" v-model="inputVal" class="flex-grow-1 border colorInputPick" type="text"
|
|
45
|
+
:placeholder="$t('color.placeholder')"
|
|
45
46
|
>
|
|
46
|
-
<Btn
|
|
47
|
+
<Btn
|
|
48
|
+
:class="{ 'not-allowed opacity-3': !inputVal }" round flat thin icon="clear"
|
|
49
|
+
@click="inputVal = ''"
|
|
50
|
+
/>
|
|
47
51
|
</div>
|
|
48
52
|
</label>
|
|
49
53
|
</div>
|
|
50
54
|
</template>
|
|
51
55
|
|
|
52
56
|
<style>
|
|
53
|
-
.colorInputPick{
|
|
57
|
+
.colorInputPick {
|
|
54
58
|
--input-font-size: 12px;
|
|
55
59
|
background: transparent !important;
|
|
56
60
|
height: var(--input-height) !important;
|
|
57
61
|
min-width: 50px !important;
|
|
58
62
|
}
|
|
59
|
-
|
|
63
|
+
|
|
64
|
+
.colorInputPick:focus {
|
|
60
65
|
outline: none;
|
|
61
66
|
box-shadow: none !important;
|
|
62
67
|
}
|
|
68
|
+
|
|
63
69
|
.colorInputPickWrap:focus-within {
|
|
64
70
|
box-shadow: inset 0 0 10px #00000021;
|
|
65
71
|
outline-color: var(--input-bg);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { ModeType } from '../../../utils/calendar/typings'
|
|
3
|
-
import { TextInput, Dropdown, formatDate } from '@bagelink/vue'
|
|
3
|
+
import { TextInput, Dropdown, formatDate, useI18n } from '@bagelink/vue'
|
|
4
4
|
import { onClickOutside } from '@vueuse/core'
|
|
5
5
|
import { ref, onMounted, watch } from 'vue'
|
|
6
6
|
import { WEEK_START_DAY } from '../../../utils/calendar/time'
|
|
@@ -37,6 +37,8 @@ const props = withDefaults(
|
|
|
37
37
|
},
|
|
38
38
|
)
|
|
39
39
|
|
|
40
|
+
const { $t } = useI18n()
|
|
41
|
+
|
|
40
42
|
const selectedDate = defineModel<string | Date>()
|
|
41
43
|
const inputValue = ref('')
|
|
42
44
|
const isValid = ref(true)
|
|
@@ -181,9 +183,10 @@ onMounted(() => {
|
|
|
181
183
|
<TextInput
|
|
182
184
|
v-model="inputValue" iconStart="calendar"
|
|
183
185
|
:placeholder="enableTime ? 'DD.MM.YY HH:mm' : 'DD.MM.YY'" :required="required"
|
|
184
|
-
:disabled="!editMode" :error="!isValid ? '
|
|
185
|
-
:class="{ 'txt-center': center }" class="date-input m-0" @input="handleInput"
|
|
186
|
-
@blur="handleBlur" @click.stop @keydown="handleKeydown"
|
|
186
|
+
:disabled="!editMode" :error="!isValid ? $t('date.invalidFormat') : error"
|
|
187
|
+
:class="{ 'txt-center': center }" class="date-input m-0" @input="handleInput"
|
|
188
|
+
@focus="handleFocus" @blur="handleBlur" @click.stop @keydown="handleKeydown"
|
|
189
|
+
@iconClick="handleIconClick"
|
|
187
190
|
/>
|
|
188
191
|
</div>
|
|
189
192
|
</template>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { IconType, ValidateInputBaseT } from '@bagelink/vue'
|
|
3
|
-
import { Icon, useDebounceFn } from '@bagelink/vue'
|
|
3
|
+
import { Icon, useDebounceFn, useI18n } from '@bagelink/vue'
|
|
4
4
|
import { onMounted, ref, watch, nextTick } from 'vue'
|
|
5
5
|
import { EMAIL_REGEX } from '../../../utils/constants'
|
|
6
6
|
|
|
@@ -17,6 +17,8 @@ const props = withDefaults(
|
|
|
17
17
|
|
|
18
18
|
const emit = defineEmits(['update:modelValue', 'debounce'])
|
|
19
19
|
|
|
20
|
+
const { $t } = useI18n()
|
|
21
|
+
|
|
20
22
|
export interface EmailInputProps extends ValidateInputBaseT {
|
|
21
23
|
id?: string
|
|
22
24
|
title?: string
|
|
@@ -108,7 +110,7 @@ function validateEmail(value: string) {
|
|
|
108
110
|
|
|
109
111
|
// Basic format validation
|
|
110
112
|
if (!EMAIL_REGEX.test(value)) {
|
|
111
|
-
return '
|
|
113
|
+
return $t('email.invalidEmail')
|
|
112
114
|
}
|
|
113
115
|
|
|
114
116
|
// Check for fake email providers if enabled
|
|
@@ -173,7 +175,7 @@ async function validateEmailWithServer(email: string) {
|
|
|
173
175
|
validatedEmails.set(email, isValid)
|
|
174
176
|
|
|
175
177
|
if (!isValid) {
|
|
176
|
-
validationMessage.value = '
|
|
178
|
+
validationMessage.value = $t('email.invalidDomain')
|
|
177
179
|
input.value?.setCustomValidity(validationMessage.value)
|
|
178
180
|
} else {
|
|
179
181
|
input.value?.setCustomValidity('')
|
|
@@ -467,9 +469,9 @@ onMounted(() => {
|
|
|
467
469
|
.error-message {
|
|
468
470
|
color: var(--bgl-red, #dc3545);
|
|
469
471
|
font-size: 10px;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
472
|
+
position: absolute;
|
|
473
|
+
inset-inline-end: 0;
|
|
474
|
+
bottom: -0.9rem;
|
|
475
|
+
margin-top: 0.25rem;
|
|
474
476
|
}
|
|
475
477
|
</style>
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { IconType } from '@bagelink/vue'
|
|
3
|
-
import { Btn, TextInput } from '@bagelink/vue'
|
|
3
|
+
import { Btn, TextInput, useI18n } from '@bagelink/vue'
|
|
4
4
|
import { zxcvbn } from '@zxcvbn-ts/core'
|
|
5
5
|
import { computed } from 'vue'
|
|
6
6
|
|
|
7
|
+
const props = withDefaults(
|
|
8
|
+
defineProps<TextInputProps>(),
|
|
9
|
+
{
|
|
10
|
+
autocomplete: 'current-password',
|
|
11
|
+
label: '',
|
|
12
|
+
strengthMeter: false
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
const { $t } = useI18n()
|
|
17
|
+
|
|
7
18
|
export interface TextInputProps {
|
|
8
19
|
id?: string
|
|
9
20
|
title?: string
|
|
@@ -31,15 +42,6 @@ export interface TextInputProps {
|
|
|
31
42
|
strengthMeter?: boolean
|
|
32
43
|
error?: string
|
|
33
44
|
}
|
|
34
|
-
const props = withDefaults(
|
|
35
|
-
defineProps<TextInputProps>(),
|
|
36
|
-
{
|
|
37
|
-
autocomplete: 'current-password',
|
|
38
|
-
label: '',
|
|
39
|
-
strengthMeter: false
|
|
40
|
-
}
|
|
41
|
-
)
|
|
42
|
-
|
|
43
45
|
const password = defineModel<string>('modelValue')
|
|
44
46
|
const showPwd = defineModel<boolean>('showPwd', { default: false })
|
|
45
47
|
|
|
@@ -73,11 +75,11 @@ const strengthColor = computed(() => {
|
|
|
73
75
|
const strengthLabel = computed(() => {
|
|
74
76
|
const score = strengthScore.value
|
|
75
77
|
if (score == null) return ''
|
|
76
|
-
if (score === 0) return '
|
|
77
|
-
if (score === 1) return '
|
|
78
|
-
if (score === 2) return '
|
|
79
|
-
if (score === 3) return '
|
|
80
|
-
return '
|
|
78
|
+
if (score === 0) return $t('password.veryWeak')
|
|
79
|
+
if (score === 1) return $t('password.weak')
|
|
80
|
+
if (score === 2) return $t('password.fair')
|
|
81
|
+
if (score === 3) return $t('password.good')
|
|
82
|
+
return $t('password.strong')
|
|
81
83
|
})
|
|
82
84
|
|
|
83
85
|
const strengthPercentage = computed(() => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Option } from '@bagelink/vue'
|
|
3
|
-
|
|
3
|
+
import { useI18n } from '@bagelink/vue'
|
|
4
4
|
import { onMounted, ref, watch } from 'vue'
|
|
5
5
|
|
|
6
6
|
const props = withDefaults(
|
|
@@ -19,17 +19,19 @@ const props = withDefaults(
|
|
|
19
19
|
|
|
20
20
|
const emits = defineEmits(['update:modelValue'])
|
|
21
21
|
|
|
22
|
+
const { $t } = useI18n()
|
|
23
|
+
|
|
22
24
|
function getLabel(option: Option) {
|
|
23
25
|
if (typeof option === 'string') { return option }
|
|
24
26
|
if (typeof option === 'number') { return `${option}` }
|
|
25
|
-
if (typeof option === 'boolean') { return option ? '
|
|
27
|
+
if (typeof option === 'boolean') { return option ? $t('select.yes') : $t('select.no') }
|
|
26
28
|
return option.label
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
function getValue(option: Option) {
|
|
30
32
|
if (typeof option === 'string') { return option }
|
|
31
33
|
if (typeof option === 'number') { return option }
|
|
32
|
-
if (typeof option === 'boolean') { return option ? '
|
|
34
|
+
if (typeof option === 'boolean') { return option ? $t('select.yes') : $t('select.no') }
|
|
33
35
|
return option.value
|
|
34
36
|
}
|
|
35
37
|
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
2
|
import type { IconType, Option } from '@bagelink/vue'
|
|
3
3
|
import type { AlignedPlacement } from '../../Dropdown.vue'
|
|
4
|
-
import { Btn, Card, Skeleton, Dropdown, Icon, TextInput, useSearch } from '@bagelink/vue'
|
|
4
|
+
import { Btn, Card, Skeleton, Dropdown, Icon, TextInput, useSearch, useI18n } from '@bagelink/vue'
|
|
5
5
|
import { computed, onMounted, ref, watch } from 'vue'
|
|
6
6
|
import 'floating-vue/style.css'
|
|
7
7
|
|
|
8
|
-
type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)
|
|
9
8
|
const props = withDefaults(defineProps<PropTypes>(), {
|
|
10
|
-
placeholder: 'Select',
|
|
11
9
|
placement: 'bottom-start',
|
|
12
10
|
})
|
|
13
11
|
|
|
14
12
|
const emit = defineEmits(['update:modelValue'])
|
|
15
13
|
|
|
14
|
+
const { $t } = useI18n()
|
|
15
|
+
|
|
16
|
+
type OptionsSource = Option[] | ((query: string) => Promise<Option[]>)
|
|
16
17
|
const isAsyncSource = (src: OptionsSource): src is (q: string) => Promise<Option[]> => typeof src === 'function'
|
|
17
18
|
|
|
18
19
|
type Primitive = string | number | boolean
|
|
@@ -47,9 +48,10 @@ const searchTerm = ref<string>('')
|
|
|
47
48
|
const dropdown = ref<InstanceType<typeof Dropdown> | undefined>()
|
|
48
49
|
const selected = ref(false)
|
|
49
50
|
const open = ref(false)
|
|
51
|
+
const selectPlaceholder = computed(() => props.placeholder ?? $t('select.placeholder'))
|
|
50
52
|
|
|
51
53
|
const selectedLabel = computed((): string => {
|
|
52
|
-
if (selectedItemCount.value === 0) { return
|
|
54
|
+
if (selectedItemCount.value === 0) { return selectPlaceholder.value }
|
|
53
55
|
if (selectedItemCount.value > 4) {
|
|
54
56
|
const str = selectedItems.value
|
|
55
57
|
.slice(0, 4)
|
|
@@ -59,8 +61,8 @@ const selectedLabel = computed((): string => {
|
|
|
59
61
|
}
|
|
60
62
|
return selectedItems.value.map(item => getLabel(item)).join(', ')
|
|
61
63
|
})
|
|
62
|
-
const searchPlaceholder = computed(() => props.searchPlaceholder ?? selectedLabel.value ?? 'Search')
|
|
63
64
|
|
|
65
|
+
const searchPlaceholder = computed(() => props.searchPlaceholder ?? selectedLabel.value ?? $t('select.search'))
|
|
64
66
|
const { results, isLoading } = useSearch<Option>({
|
|
65
67
|
searchTerm: () => searchTerm.value,
|
|
66
68
|
serverSearch: isAsyncSource(props.options) ? props.options : undefined,
|
|
@@ -113,8 +115,8 @@ function scrollToSelectedItem() {
|
|
|
113
115
|
function getLabel(option: Option) {
|
|
114
116
|
if (option == null) { return '' }
|
|
115
117
|
if (typeof option === 'object') { return option.label ?? String((option as any).value ?? '') }
|
|
116
|
-
if (option === true) { return '
|
|
117
|
-
if (option === false) { return '
|
|
118
|
+
if (option === true) { return $t('select.yes') }
|
|
119
|
+
if (option === false) { return $t('select.no') }
|
|
118
120
|
return String(option)
|
|
119
121
|
}
|
|
120
122
|
|
|
@@ -433,9 +435,9 @@ onMounted(() => {
|
|
|
433
435
|
.error-message {
|
|
434
436
|
color: var(--bgl-red, #dc3545);
|
|
435
437
|
font-size: 10px;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
438
|
+
position: absolute;
|
|
439
|
+
inset-inline-end: 0;
|
|
440
|
+
bottom: -0.9rem;
|
|
441
|
+
margin-top: 0.25rem;
|
|
440
442
|
}
|
|
441
443
|
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Country } from '@bagelink/vue'
|
|
3
3
|
import type { CountryCode } from 'libphonenumber-js'
|
|
4
|
-
import { Dropdown, Flag, Icon, TextInput, allCountries, ipapi } from '@bagelink/vue'
|
|
4
|
+
import { Dropdown, Flag, Icon, TextInput, allCountries, ipapi, useI18n } from '@bagelink/vue'
|
|
5
5
|
import { parsePhoneNumberFromString } from 'libphonenumber-js'
|
|
6
6
|
import { computed, onMounted, ref, watch } from 'vue'
|
|
7
7
|
|
|
@@ -19,6 +19,8 @@ const props = defineProps<{
|
|
|
19
19
|
|
|
20
20
|
const emit = defineEmits(['update:modelValue', 'blur', 'focus', 'keydown', 'input', 'paste'])
|
|
21
21
|
|
|
22
|
+
const { $t } = useI18n()
|
|
23
|
+
|
|
22
24
|
const phoneNumber = ref(props.modelValue ?? '')
|
|
23
25
|
const search = ref('')
|
|
24
26
|
const activeCountry = ref<Country>()
|
|
@@ -64,9 +66,9 @@ const activeCountryCode = computed(() => activeCountry.value?.iso2)
|
|
|
64
66
|
const computedPlaceholder = computed(() => {
|
|
65
67
|
if (props.placeholder) return props.placeholder
|
|
66
68
|
if (activeCountry.value) {
|
|
67
|
-
return `+${activeCountry.value.dialCode} ${props.label || '
|
|
69
|
+
return `+${activeCountry.value.dialCode} ${props.label || $t('tel.phoneNumber')}`
|
|
68
70
|
}
|
|
69
|
-
return props.label || '
|
|
71
|
+
return props.label || $t('tel.phoneNumber')
|
|
70
72
|
})
|
|
71
73
|
|
|
72
74
|
function selectCountry(country: Country) {
|
|
@@ -139,12 +141,12 @@ function validatePhoneNumber() {
|
|
|
139
141
|
inputRef.value.setCustomValidity('')
|
|
140
142
|
isValid.value = true
|
|
141
143
|
} else {
|
|
142
|
-
inputRef.value.setCustomValidity('
|
|
144
|
+
inputRef.value.setCustomValidity($t('tel.invalidPhone'))
|
|
143
145
|
isValid.value = false
|
|
144
146
|
}
|
|
145
147
|
} catch (error) {
|
|
146
148
|
console.error('Error validating phone number:', error)
|
|
147
|
-
inputRef.value.setCustomValidity('
|
|
149
|
+
inputRef.value.setCustomValidity($t('tel.invalidPhone'))
|
|
148
150
|
isValid.value = false
|
|
149
151
|
}
|
|
150
152
|
}
|
|
@@ -349,10 +351,10 @@ onMounted(initializeCountry)
|
|
|
349
351
|
.error-message {
|
|
350
352
|
color: var(--bgl-red, #dc3545);
|
|
351
353
|
font-size: 10px;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
position: absolute;
|
|
355
|
+
inset-inline-end: 0;
|
|
356
|
+
bottom: -0.9rem;
|
|
357
|
+
margin-top: 0.25rem;
|
|
356
358
|
}
|
|
357
359
|
|
|
358
360
|
@keyframes highlight-country {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { UploadInputProps } from '@bagelink/vue'
|
|
3
|
-
import { Btn, IMAGE_FORMATS_REGEXP, Icon, Card, Image, pathKeyToURL, Loading } from '@bagelink/vue'
|
|
3
|
+
import { Btn, IMAGE_FORMATS_REGEXP, Icon, Card, Image, pathKeyToURL, Loading, useI18n } from '@bagelink/vue'
|
|
4
4
|
import { watch, ref } from 'vue'
|
|
5
5
|
|
|
6
6
|
import { useFileUpload } from './useFileUpload'
|
|
@@ -15,6 +15,8 @@ const props = withDefaults(defineProps<UploadInputProps & { showIcon?: boolean,
|
|
|
15
15
|
|
|
16
16
|
const emit = defineEmits(['update:modelValue', 'addFileStart'])
|
|
17
17
|
|
|
18
|
+
const { $t } = useI18n()
|
|
19
|
+
|
|
18
20
|
const {
|
|
19
21
|
fileQueue,
|
|
20
22
|
pathKeys,
|
|
@@ -78,13 +80,13 @@ function fileName(pathKey: string) {
|
|
|
78
80
|
>
|
|
79
81
|
<Btn
|
|
80
82
|
v-if="!pathKeys.length && !fileQueue.length" class="px-1-5" icon="upload" outline
|
|
81
|
-
:value="btnPlaceholder || '
|
|
83
|
+
:value="btnPlaceholder || $t('upload.upload')" @click="browse()"
|
|
82
84
|
/>
|
|
83
85
|
<!-- Loading state during upload -->
|
|
84
86
|
<div v-if="fileQueue.length > 0" class="flex align-items-center gap-1 p-05">
|
|
85
87
|
<Loading size="20" />
|
|
86
88
|
<span class="txt-gray txt-12">
|
|
87
|
-
|
|
89
|
+
{{ $t('upload.uploading', { count: fileQueue.length, plural: fileQueue.length > 1 ? 's' : '' }) }}
|
|
88
90
|
</span>
|
|
89
91
|
</div>
|
|
90
92
|
|
|
@@ -111,7 +113,7 @@ function fileName(pathKey: string) {
|
|
|
111
113
|
</template>
|
|
112
114
|
|
|
113
115
|
<span v-if="!pathKeys.length && !fileQueue.length" class="txt-gray txt-12">
|
|
114
|
-
{{ noFilePlaceholder || '
|
|
116
|
+
{{ noFilePlaceholder || $t('upload.noFile') }}
|
|
115
117
|
</span>
|
|
116
118
|
</Card>
|
|
117
119
|
|
|
@@ -208,7 +210,7 @@ function fileName(pathKey: string) {
|
|
|
208
210
|
<p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
|
|
209
211
|
<Icon v-if="showIcon" :name="icon" class="user-select-none" />
|
|
210
212
|
<span class=" pretty balance user-select-none ">
|
|
211
|
-
{{ dropPlaceholder || '
|
|
213
|
+
{{ dropPlaceholder || $t('upload.dropPlaceholder') }}
|
|
212
214
|
</span>
|
|
213
215
|
</p>
|
|
214
216
|
</slot>
|
|
@@ -3,6 +3,9 @@ import type { LightboxItem } from './lightbox.types'
|
|
|
3
3
|
|
|
4
4
|
import { BglVideo, Btn, Icon, Zoomer, Image, normalizeURL, Swiper, downloadFile } from '@bagelink/vue'
|
|
5
5
|
import { computed, ref, watch } from 'vue'
|
|
6
|
+
import { useI18n } from '../../i18n'
|
|
7
|
+
|
|
8
|
+
const { $t } = useI18n()
|
|
6
9
|
|
|
7
10
|
const isOpen = ref(false)
|
|
8
11
|
const group = ref<LightboxItem[]>([])
|
|
@@ -79,7 +82,7 @@ defineExpose({ open, close })
|
|
|
79
82
|
</div>
|
|
80
83
|
<Btn
|
|
81
84
|
v-if="currentItem?.openFile && currentItem?.src" class="color-white" round thin flat
|
|
82
|
-
iconEnd="arrow_outward" value="
|
|
85
|
+
iconEnd="arrow_outward" value="$t:lightbox.openFile" :href="currentItem?.src" target="_blank"
|
|
83
86
|
/>
|
|
84
87
|
<Btn
|
|
85
88
|
v-if="currentItem?.download && currentItem?.src" class="color-white" round thin flat
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* DialogConfirm - Simple confirmation dialog
|
|
4
4
|
*/
|
|
5
5
|
import type { DialogWidth, DialogPosition } from './dialogTypes'
|
|
6
|
+
import { useI18n } from '@bagelink/vue'
|
|
7
|
+
import { computed } from 'vue'
|
|
6
8
|
import Btn from '../components/Btn.vue'
|
|
7
9
|
import Dialog from './Dialog.vue'
|
|
8
10
|
|
|
@@ -17,12 +19,9 @@ const props = withDefaults(defineProps<{
|
|
|
17
19
|
cancelText?: string
|
|
18
20
|
confirmColor?: 'primary' | 'red' | 'green' | 'blue'
|
|
19
21
|
}>(), {
|
|
20
|
-
title: 'Confirm',
|
|
21
22
|
width: 's',
|
|
22
23
|
position: 'center',
|
|
23
24
|
dismissable: true,
|
|
24
|
-
confirmText: 'Confirm',
|
|
25
|
-
cancelText: 'Cancel',
|
|
26
25
|
confirmColor: 'primary'
|
|
27
26
|
})
|
|
28
27
|
|
|
@@ -31,6 +30,12 @@ const emit = defineEmits<{
|
|
|
31
30
|
'resolve': [confirmed: boolean]
|
|
32
31
|
}>()
|
|
33
32
|
|
|
33
|
+
const { $t } = useI18n()
|
|
34
|
+
|
|
35
|
+
const resolvedTitle = computed(() => props.title || $t('modalConfirm.title'))
|
|
36
|
+
const resolvedConfirmText = computed(() => props.confirmText || $t('modalConfirm.confirm'))
|
|
37
|
+
const resolvedCancelText = computed(() => props.cancelText || $t('modalConfirm.cancel'))
|
|
38
|
+
|
|
34
39
|
function handleConfirm() {
|
|
35
40
|
emit('resolve', true)
|
|
36
41
|
emit('update:open', false)
|
|
@@ -48,7 +53,7 @@ function handleClose() {
|
|
|
48
53
|
|
|
49
54
|
<template>
|
|
50
55
|
<Dialog
|
|
51
|
-
:open="open" :title="
|
|
56
|
+
:open="open" :title="resolvedTitle" :width="width" :position="position" :dismissable="dismissable"
|
|
52
57
|
@update:open="$emit('update:open', $event)" @close="handleClose"
|
|
53
58
|
>
|
|
54
59
|
<p>
|
|
@@ -57,10 +62,10 @@ function handleClose() {
|
|
|
57
62
|
|
|
58
63
|
<template #footer>
|
|
59
64
|
<Btn flat @click="handleCancel">
|
|
60
|
-
{{
|
|
65
|
+
{{ resolvedCancelText }}
|
|
61
66
|
</Btn>
|
|
62
67
|
<Btn :color="confirmColor" @click="handleConfirm">
|
|
63
|
-
{{
|
|
68
|
+
{{ resolvedConfirmText }}
|
|
64
69
|
</Btn>
|
|
65
70
|
</template>
|
|
66
71
|
</Dialog>
|