@bagelink/vue 1.9.51 → 1.9.56
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 +995 -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 +15388 -11464
- package/dist/plugins/bagel.d.ts +5 -7
- package/dist/plugins/bagel.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/utils/calendar/dateUtils.d.ts +6 -5
- 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/calendar/views/AgendaView.vue +1 -1
- package/src/components/calendar/views/DayView.vue +3 -3
- package/src/components/calendar/views/MonthView.vue +1 -1
- package/src/components/calendar/views/WeekView.vue +6 -6
- package/src/components/form/FieldArray.vue +4 -2
- package/src/components/form/inputs/ColorInput.vue +18 -12
- package/src/components/form/inputs/DateInput.vue +8 -5
- 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 +136 -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/styles/text.css +2 -1
- package/src/utils/calendar/dateUtils.ts +108 -63
- 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>
|
|
@@ -165,7 +165,7 @@ onUnmounted(() => {
|
|
|
165
165
|
>
|
|
166
166
|
<div class="event-content">
|
|
167
167
|
<div class="event-time">
|
|
168
|
-
{{ formatDate(event.start_time, {
|
|
168
|
+
{{ formatDate(event.start_time, { format: 'HH:mm' }) }}
|
|
169
169
|
</div>
|
|
170
170
|
<div class="event-details">
|
|
171
171
|
<div class="event-title">
|
|
@@ -233,7 +233,7 @@ onUnmounted(() => {
|
|
|
233
233
|
{{ event.title }}
|
|
234
234
|
</div>
|
|
235
235
|
<div class="event-time opacity-8">
|
|
236
|
-
{{ formatDate(new Date(event.start_time), {
|
|
236
|
+
{{ formatDate(new Date(event.start_time), { format: 'HH:mm' }) }} - {{ formatDate(new Date(event.end_time), { format: 'HH:mm' }) }}
|
|
237
237
|
</div>
|
|
238
238
|
</div>
|
|
239
239
|
</div>
|
|
@@ -251,9 +251,9 @@ onUnmounted(() => {
|
|
|
251
251
|
}"
|
|
252
252
|
>
|
|
253
253
|
<div class="color-primary txt-12 p-025">
|
|
254
|
-
{{ dragState.startTime ? formatDate(dragState.startTime, {
|
|
254
|
+
{{ dragState.startTime ? formatDate(dragState.startTime, { format: 'HH:mm' }) : '' }}
|
|
255
255
|
-
|
|
256
|
-
{{ dragState.endTime ? formatDate(dragState.endTime, {
|
|
256
|
+
{{ dragState.endTime ? formatDate(dragState.endTime, { format: 'HH:mm' }) : '' }}
|
|
257
257
|
</div>
|
|
258
258
|
</div>
|
|
259
259
|
</div>
|
|
@@ -122,7 +122,7 @@ function handleEventSelection(event: CalendarEvent, domEvent?: MouseEvent) {
|
|
|
122
122
|
}"
|
|
123
123
|
>
|
|
124
124
|
<div class="day-number">
|
|
125
|
-
{{ formatDate(day.date, {
|
|
125
|
+
{{ formatDate(day.date, { format: 'DD' }) }}
|
|
126
126
|
</div>
|
|
127
127
|
<div class="day-events">
|
|
128
128
|
<template v-if="isMobile">
|
|
@@ -432,14 +432,14 @@ onUnmounted(() => {
|
|
|
432
432
|
<div ref="calendarGrid" class="weekGrid border-bottom me-1">
|
|
433
433
|
<div />
|
|
434
434
|
<div v-for="day in weekDays" :key="day.toISOString()" class="day-header p-05 txt-center m_txt12">
|
|
435
|
-
{{ formatDate(day, {
|
|
435
|
+
{{ formatDate(day, { format: 'DDD' }) }}
|
|
436
436
|
<span
|
|
437
437
|
class="txt-12 round p-025" :class="{
|
|
438
438
|
'color-gray': day.toDateString() !== new Date().toDateString(),
|
|
439
439
|
'bg-primary color-white': day.toDateString() === new Date().toDateString(),
|
|
440
440
|
}"
|
|
441
441
|
>
|
|
442
|
-
{{ formatDate(day, {
|
|
442
|
+
{{ formatDate(day, { format: 'DD' }) }}
|
|
443
443
|
</span>
|
|
444
444
|
</div>
|
|
445
445
|
</div>
|
|
@@ -487,8 +487,8 @@ onUnmounted(() => {
|
|
|
487
487
|
{{ event.title }}
|
|
488
488
|
</div>
|
|
489
489
|
<div class="txt10 opacity-8 user-select-none">
|
|
490
|
-
{{ formatDate(event.start_time, {
|
|
491
|
-
{
|
|
490
|
+
{{ formatDate(event.start_time, { format: 'HH:mm' }) }} - {{ formatDate(event.end_time,
|
|
491
|
+
{ format: 'HH:mm' }) }}
|
|
492
492
|
</div>
|
|
493
493
|
</div>
|
|
494
494
|
</div>
|
|
@@ -507,9 +507,9 @@ onUnmounted(() => {
|
|
|
507
507
|
}"
|
|
508
508
|
>
|
|
509
509
|
<div class="color-primary txt-12 p-025">
|
|
510
|
-
{{ dragState.startTime ? formatDate(dragState.startTime, {
|
|
510
|
+
{{ dragState.startTime ? formatDate(dragState.startTime, { format: 'HH:mm' }) : '' }} - {{
|
|
511
511
|
dragState.endTime
|
|
512
|
-
? formatDate(dragState.endTime, {
|
|
512
|
+
? formatDate(dragState.endTime, { format: 'HH:mm' }) : '' }}
|
|
513
513
|
</div>
|
|
514
514
|
</div>
|
|
515
515
|
</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)
|
|
@@ -46,7 +48,7 @@ const isOpen = ref(false)
|
|
|
46
48
|
// Formatting utilities
|
|
47
49
|
function formatDisplayDate(date: Date | string | undefined): string {
|
|
48
50
|
if (date === undefined || date === '') return ''
|
|
49
|
-
return formatDate(date, {
|
|
51
|
+
return formatDate(date, { format: props.enableTime ? 'DD.MM.YY HH:mm' : 'DD.MM.YY' })
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
function parseUserInput(input: string): Date | null {
|
|
@@ -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 {
|