@amirjalili1374/ui-kit 1.2.0 → 1.2.2
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 +11 -11
- package/package.json +3 -3
- package/src/assets/fonts/A Massir Spray.ttf +0 -0
- package/src/assets/fonts/BYekan.ttf +0 -0
- package/src/assets/fonts/BYekan.woff +0 -0
- package/src/assets/fonts/BYekan.woff2 +0 -0
- package/src/assets/fonts/Dima Shekasteh 2 Free.ttf +0 -0
- package/src/assets/fonts/Dima Shekasteh Free Regular.ttf +0 -0
- package/src/assets/fonts/IRANSansWeb.ts +0 -1
- package/src/assets/fonts/IRANSansWeb.ttf +0 -0
- package/src/assets/fonts/IRANSansXBlack.ttf +0 -0
- package/src/assets/fonts/IRANSansXBold.ttf +0 -0
- package/src/assets/fonts/IRANSansXDemiBold.ttf +0 -0
- package/src/assets/fonts/IRANSansXExtraBold.ttf +0 -0
- package/src/assets/fonts/IRANSansXLight.ttf +0 -0
- package/src/assets/fonts/IRANSansXMedium.ttf +0 -0
- package/src/assets/fonts/IRANSansXRegular.ttf +0 -0
- package/src/assets/fonts/IRANSansXThin.ttf +0 -0
- package/src/assets/fonts/IRANSansXUltraLight.ttf +0 -0
- package/src/assets/fonts/IranNastaliq.ttf +0 -0
- package/src/assets/fonts/Vazir-Medium-FD.ttf +0 -0
- package/src/assets/fonts/Vazir-Medium-FD.woff +0 -0
- package/src/assets/fonts/Vazir-Medium-FD.woff2 +0 -0
- package/src/assets/fonts/Vazir-Regular-FD.eot +0 -0
- package/src/assets/fonts/kalamehBold.woff +0 -0
- package/src/assets/fonts/kalamehBold.woff2 +0 -0
- package/src/assets/fonts/kalamehHeavy.woff +0 -0
- package/src/assets/fonts/kalamehHeavy.woff2 +0 -0
- package/src/assets/fonts/kalamehLight.woff +0 -0
- package/src/assets/fonts/kalamehLight.woff2 +0 -0
- package/src/assets/fonts/kalamehRegular.woff +0 -0
- package/src/assets/fonts/kalamehRegular.woff2 +0 -0
- package/src/assets/images/auth/social-google.svg +0 -6
- package/src/assets/images/favicon.svg +0 -18
- package/src/assets/images/icons/icon-card.svg +0 -5
- package/src/assets/images/logos/logo.svg +0 -12
- package/src/assets/images/logos/logolight.svg +0 -12
- package/src/assets/images/maintenance/img-error-bg.svg +0 -34
- package/src/assets/images/maintenance/img-error-blue.svg +0 -43
- package/src/assets/images/maintenance/img-error-purple.svg +0 -42
- package/src/assets/images/maintenance/img-error-text.svg +0 -27
- package/src/assets/images/profile/profile-user-account-svgrepo-com.svg +0 -12
- package/src/assets/images/profile/user-round.svg +0 -15
- package/src/assets/images/template/template-01.ts +0 -1
- package/src/assets/images/vectors/colorized-bg.svg +0 -40
- package/src/assets/images/vectors/logo_stroke_1px.svg +0 -26
- package/src/assets/images/vectors/logo_stroke_2px.svg +0 -26
- package/src/assets/scss/components/_approval-sections.scss +0 -75
- package/src/assets/styles/fonts.scss +0 -77
- package/src/components/Loading.vue +0 -88
- package/src/components/common/AppStepper.vue +0 -139
- package/src/components/shared/BaseBreadcrumb.vue +0 -55
- package/src/components/shared/BaseIcon.vue +0 -27
- package/src/components/shared/ConfirmDialog.vue +0 -72
- package/src/components/shared/CustomAutocomplete.vue +0 -306
- package/src/components/shared/CustomDataTable.vue +0 -1859
- package/src/components/shared/DescriptionInput.vue +0 -204
- package/src/components/shared/DownloadButton.vue +0 -169
- package/src/components/shared/MoneyInput.vue +0 -105
- package/src/components/shared/PdfViewer.vue +0 -645
- package/src/components/shared/ShamsiDatePicker.vue +0 -444
- package/src/components/shared/UiChildCard.vue +0 -17
- package/src/components/shared/UiParentCard.vue +0 -21
- package/src/components/shared/VPriceTextField.vue +0 -136
- package/src/composables/useDataTable.ts +0 -152
- package/src/composables/usePermissions.ts +0 -90
- package/src/composables/useRouteGuard.ts +0 -36
- package/src/composables/useTableActions.ts +0 -207
- package/src/composables/useTableHeaders.ts +0 -172
- package/src/composables/useTableSelection.ts +0 -201
- package/src/constants/enums/approval.ts +0 -13
- package/src/constants/enums/booleanEnum.ts +0 -11
- package/src/constants/enums/contractType.ts +0 -11
- package/src/constants/enums/lcProductType.ts +0 -21
- package/src/constants/enums/repaymentType.ts +0 -11
- package/src/directives/v-digit-limit.ts +0 -15
- package/src/directives/v-permission.ts +0 -31
- package/src/features/index.ts +0 -48
- package/src/index.ts +0 -119
- package/src/plugins/key-clock.ts +0 -39
- package/src/plugins/mdi-icon.ts +0 -31
- package/src/plugins/vuetify.ts +0 -74
- package/src/scss/_override.scss +0 -72
- package/src/scss/_variables.scss +0 -124
- package/src/scss/components/_VButtons.scss +0 -23
- package/src/scss/components/_VCard.scss +0 -20
- package/src/scss/components/_VCustomDataTable.scss +0 -282
- package/src/scss/components/_VField.scss +0 -9
- package/src/scss/components/_VInput.scss +0 -17
- package/src/scss/components/_VNavigationDrawer.scss +0 -3
- package/src/scss/components/_VShadow.scss +0 -3
- package/src/scss/components/_VStepper.scss +0 -235
- package/src/scss/components/_VTabs.scss +0 -11
- package/src/scss/components/_VTextField.scss +0 -40
- package/src/scss/components/_approval.scss +0 -128
- package/src/scss/layout/_container.scss +0 -147
- package/src/scss/layout/_sidebar.scss +0 -138
- package/src/scss/layout/_topbar.scss +0 -39
- package/src/scss/pages/_dashboards.scss +0 -97
- package/src/scss/style.scss +0 -21
- package/src/services/apiService.ts +0 -59
- package/src/services/axiosInstance.ts +0 -14
- package/src/stores/customizer.ts +0 -55
- package/src/stores/permissions.ts +0 -237
- package/src/theme/darkThemes/DarkModernTheme.ts +0 -54
- package/src/theme/darkThemes/DarkOrangeTheme.ts +0 -53
- package/src/theme/darkThemes/DarkPurpleTheme.ts +0 -54
- package/src/theme/darkThemes/DarkRedTheme.ts +0 -54
- package/src/theme/darkThemes/DarkSilverTheme.ts +0 -53
- package/src/theme/darkThemes/DarkSteelTealGreen.ts +0 -53
- package/src/theme/darkThemes/DarkTealTheme.ts +0 -52
- package/src/theme/lightThemes/ModernTheme.ts +0 -55
- package/src/theme/lightThemes/OrangeTheme.ts +0 -54
- package/src/theme/lightThemes/PurpleTheme.ts +0 -54
- package/src/theme/lightThemes/RedTheme.ts +0 -55
- package/src/theme/lightThemes/SilverTheme.ts +0 -55
- package/src/theme/lightThemes/SteelTealGreen.ts +0 -54
- package/src/theme/lightThemes/TealTheme.ts +0 -54
- package/src/types/approval/approvalType.ts +0 -473
- package/src/types/cartable/cartableTypes.ts +0 -169
- package/src/types/componentTypes/DataTableType.ts +0 -14
- package/src/types/componentTypes/DataTableTypes.ts +0 -130
- package/src/types/enums/global.ts +0 -267
- package/src/types/jalaali-js.d.ts +0 -6
- package/src/types/models/Base.ts +0 -4
- package/src/types/models/env.d.ts +0 -10
- package/src/types/models/person.ts +0 -13
- package/src/types/models/userInfo.ts +0 -29
- package/src/types/preApproval/preApprovalTypes.ts +0 -67
- package/src/types/shims-tabler-icons.d.ts +0 -58
- package/src/types/themeTypes/ThemeType.ts +0 -47
- package/src/types/vue-apexcharts.d.ts +0 -1
- package/src/types/vue3-print-nb.d.ts +0 -1
- package/src/types/vue_tabler_icon.d.ts +0 -10
- package/src/utils/NationalCodeValidator.ts +0 -33
- package/src/utils/date-convertor.ts +0 -40
- package/src/utils/greetingUtils.ts +0 -97
- package/src/utils/helpers/fake-backend.ts +0 -68
- package/src/utils/helpers/fetch-wrapper.ts +0 -86
- package/src/utils/number-formatter.ts +0 -33
- package/src/validators/nationalCodeRule.ts +0 -6
|
@@ -1,444 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="shamsi-date-picker">
|
|
3
|
-
<Vue3PersianDatetimePicker
|
|
4
|
-
:label="label"
|
|
5
|
-
v-model="selectedDate"
|
|
6
|
-
:format="format"
|
|
7
|
-
:display-format="displayFormat"
|
|
8
|
-
:editable="false"
|
|
9
|
-
:clearable="clearable"
|
|
10
|
-
:disabled="disabled"
|
|
11
|
-
:min="minDate"
|
|
12
|
-
:max="maxDate"
|
|
13
|
-
:placeholder="placeholder"
|
|
14
|
-
:input-class="inputClass"
|
|
15
|
-
:wrapper-class="wrapperClass"
|
|
16
|
-
:range="isRangeMode"
|
|
17
|
-
:color="color"
|
|
18
|
-
@change="onDateChange"
|
|
19
|
-
/>
|
|
20
|
-
</div>
|
|
21
|
-
</template>
|
|
22
|
-
|
|
23
|
-
<script setup lang="ts">
|
|
24
|
-
import { computed } from 'vue';
|
|
25
|
-
|
|
26
|
-
interface Props {
|
|
27
|
-
modelValue?: string | [string, string] | null; // Single date or range
|
|
28
|
-
label?: string;
|
|
29
|
-
placeholder?: string;
|
|
30
|
-
variant?: 'outlined' | 'filled' | 'plain' | 'underlined' | 'solo' | 'solo-inverted' | 'solo-filled';
|
|
31
|
-
density?: 'default' | 'comfortable' | 'compact' | 'prominent';
|
|
32
|
-
color?: string;
|
|
33
|
-
disabled?: boolean;
|
|
34
|
-
readonly?: boolean;
|
|
35
|
-
clearable?: boolean;
|
|
36
|
-
rules?: any[];
|
|
37
|
-
hideDetails?: boolean | 'auto';
|
|
38
|
-
prependInnerIcon?: string;
|
|
39
|
-
appendInnerIcon?: string;
|
|
40
|
-
format?: string;
|
|
41
|
-
displayFormat?: string;
|
|
42
|
-
minDate?: string;
|
|
43
|
-
maxDate?: string;
|
|
44
|
-
mode?: 'single' | 'range'; // Single date or range picker
|
|
45
|
-
icon?: string; // Custom calendar icon
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const props = withDefaults(defineProps<Props>(), {
|
|
49
|
-
modelValue: '',
|
|
50
|
-
label: 'تاریخ',
|
|
51
|
-
placeholder: 'تاریخ را انتخاب کنید',
|
|
52
|
-
variant: 'outlined',
|
|
53
|
-
density: 'default',
|
|
54
|
-
color: 'primary',
|
|
55
|
-
disabled: false,
|
|
56
|
-
readonly: false,
|
|
57
|
-
clearable: true,
|
|
58
|
-
rules: () => [],
|
|
59
|
-
hideDetails: 'auto',
|
|
60
|
-
prependInnerIcon: '',
|
|
61
|
-
appendInnerIcon: '',
|
|
62
|
-
format: 'YYYY-MM-DD',
|
|
63
|
-
displayFormat: 'jYYYY/jMM/jDD',
|
|
64
|
-
minDate: '',
|
|
65
|
-
maxDate: '',
|
|
66
|
-
mode: 'single',
|
|
67
|
-
icon: ''
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const emit = defineEmits<{
|
|
71
|
-
'update:modelValue': [value: string | [string, string] | null];
|
|
72
|
-
}>();
|
|
73
|
-
|
|
74
|
-
const selectedDate = computed({
|
|
75
|
-
get: () => {
|
|
76
|
-
// Pass Gregorian date directly to the library, let it handle Shamsi display
|
|
77
|
-
if (props.mode === 'range' && Array.isArray(props.modelValue)) {
|
|
78
|
-
return props.modelValue;
|
|
79
|
-
} else if (typeof props.modelValue === 'string' && props.modelValue) {
|
|
80
|
-
console.log('Passing Gregorian date to picker:', props.modelValue);
|
|
81
|
-
// Convert ISO string to local date to avoid timezone issues
|
|
82
|
-
if (props.modelValue.includes('T')) {
|
|
83
|
-
const date = new Date(props.modelValue);
|
|
84
|
-
// Format as YYYY-MM-DD to avoid timezone confusion
|
|
85
|
-
const localDate = date.getFullYear() + '-' +
|
|
86
|
-
String(date.getMonth() + 1).padStart(2, '0') + '-' +
|
|
87
|
-
String(date.getDate()).padStart(2, '0');
|
|
88
|
-
console.log('Converted to local date:', localDate);
|
|
89
|
-
return localDate;
|
|
90
|
-
}
|
|
91
|
-
// Otherwise, create a proper date string that the picker can handle
|
|
92
|
-
return props.modelValue + 'T00:00:00.000Z';
|
|
93
|
-
}
|
|
94
|
-
return props.modelValue;
|
|
95
|
-
},
|
|
96
|
-
set: (value) => {
|
|
97
|
-
console.log('selectedDate setter called with:', value);
|
|
98
|
-
emit('update:modelValue', value);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const onDateChange = (date: any) => {
|
|
103
|
-
console.log('Date changed:', date);
|
|
104
|
-
|
|
105
|
-
if (props.mode === 'range') {
|
|
106
|
-
// Handle range mode
|
|
107
|
-
if (Array.isArray(date) && date.length === 2) {
|
|
108
|
-
const [startDate, endDate] = date;
|
|
109
|
-
const gregorianStart = startDate && startDate._isAMomentObject ?
|
|
110
|
-
startDate.toISOString() : startDate;
|
|
111
|
-
const gregorianEnd = endDate && endDate._isAMomentObject ?
|
|
112
|
-
endDate.toISOString() : endDate;
|
|
113
|
-
|
|
114
|
-
console.log('Range - Start:', gregorianStart, 'End:', gregorianEnd);
|
|
115
|
-
emit('update:modelValue', [gregorianStart, gregorianEnd]);
|
|
116
|
-
} else {
|
|
117
|
-
emit('update:modelValue', null);
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
// Handle single date mode
|
|
121
|
-
if (date && date._isAMomentObject && date.isValid()) {
|
|
122
|
-
// Use Moment's toISOString method to get full ISO format with timezone
|
|
123
|
-
const gregorianISO = date.toISOString();
|
|
124
|
-
console.log('Single date - Gregorian for server:', gregorianISO);
|
|
125
|
-
emit('update:modelValue', gregorianISO);
|
|
126
|
-
} else if (typeof date === 'string') {
|
|
127
|
-
// If it's a string, convert to ISO format
|
|
128
|
-
const dateObj = new Date(date);
|
|
129
|
-
const gregorianISO = dateObj.toISOString();
|
|
130
|
-
console.log('String date converted to ISO:', gregorianISO);
|
|
131
|
-
emit('update:modelValue', gregorianISO);
|
|
132
|
-
} else {
|
|
133
|
-
emit('update:modelValue', '');
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
// CSS classes for Vuetify-like styling
|
|
139
|
-
const inputClass = computed(() => {
|
|
140
|
-
const classes = ['v-text-field', 'v-input', 'v-input--density-comfortable'];
|
|
141
|
-
if (props.variant === 'outlined') {
|
|
142
|
-
classes.push('v-text-field--variant-outlined');
|
|
143
|
-
}
|
|
144
|
-
return classes.join(' ');
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const wrapperClass = computed(() => {
|
|
148
|
-
return 'v-field v-field--variant-outlined v-field--density-comfortable';
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Check if range mode is enabled
|
|
152
|
-
const isRangeMode = computed(() => props.mode === 'range');
|
|
153
|
-
</script>
|
|
154
|
-
|
|
155
|
-
<style scoped>
|
|
156
|
-
.shamsi-date-picker {
|
|
157
|
-
position: relative;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/* Style the Persian date picker input to look like Vuetify */
|
|
161
|
-
.shamsi-date-picker :deep(.vpd-input-group) {
|
|
162
|
-
border: 1px solid rgb(var(--v-theme-borderLight));
|
|
163
|
-
border-radius: 10px;
|
|
164
|
-
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
165
|
-
background: rgb(var(--v-theme-surface));
|
|
166
|
-
position: relative;
|
|
167
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
.shamsi-date-picker :deep(.vpd-input-group:hover) {
|
|
171
|
-
border-color: rgb(var(--v-theme-secondary));
|
|
172
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.shamsi-date-picker :deep(.vpd-input-group:focus-within) {
|
|
176
|
-
border-color: rgb(var(--v-theme-primary));
|
|
177
|
-
box-shadow: 0 0 0 2px rgba(var(--v-theme-primary), 0.1);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
.shamsi-date-picker :deep(.vpd-input-group input) {
|
|
181
|
-
padding: 12px 16px;
|
|
182
|
-
font-size: 16px;
|
|
183
|
-
border: none;
|
|
184
|
-
outline: none;
|
|
185
|
-
background: transparent;
|
|
186
|
-
width: 100%;
|
|
187
|
-
box-sizing: border-box;
|
|
188
|
-
color: rgb(var(--v-theme-onSurface));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
.shamsi-date-picker :deep(.vpd-input-group input::placeholder) {
|
|
192
|
-
color: rgb(var(--v-theme-onSurfaceVariant));
|
|
193
|
-
opacity: 0.7;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.shamsi-date-picker :deep(.vpd-icon-btn) {
|
|
197
|
-
padding: 8px;
|
|
198
|
-
border-radius: 6px;
|
|
199
|
-
margin: 4px;
|
|
200
|
-
cursor: pointer;
|
|
201
|
-
background: linear-gradient(135deg, rgb(var(--v-theme-primary)) 0%, rgb(var(--v-theme-secondary)) 100%) !important;
|
|
202
|
-
color: white !important;
|
|
203
|
-
transition: all 0.2s ease;
|
|
204
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
.shamsi-date-picker :deep(.vpd-icon-btn:hover) {
|
|
208
|
-
transform: translateY(-1px);
|
|
209
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.shamsi-date-picker :deep(.vpd-icon-btn:active) {
|
|
213
|
-
transform: translateY(0);
|
|
214
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/* Custom icon styling */
|
|
218
|
-
.shamsi-date-picker :deep(.vpd-icon-btn i) {
|
|
219
|
-
font-size: 16px;
|
|
220
|
-
filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/* Range mode styling */
|
|
224
|
-
.shamsi-date-picker :deep(.vpd-range) {
|
|
225
|
-
background: linear-gradient(135deg, rgb(var(--v-theme-primary)) 0%, rgb(var(--v-theme-secondary)) 100%) !important;
|
|
226
|
-
opacity: 0.2;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/* Calendar popup styling */
|
|
230
|
-
.shamsi-date-picker :deep(.vpd-picker) {
|
|
231
|
-
background: rgb(var(--v-theme-surface));
|
|
232
|
-
border: 1px solid rgb(var(--v-theme-borderLight));
|
|
233
|
-
border-radius: 12px;
|
|
234
|
-
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/* Calendar header */
|
|
238
|
-
.shamsi-date-picker :deep(.vpd-header) {
|
|
239
|
-
background: linear-gradient(135deg, rgb(var(--v-theme-primary)) 0%, rgb(var(--v-theme-secondary)) 100%);
|
|
240
|
-
color: white;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/* Calendar navigation buttons */
|
|
244
|
-
.shamsi-date-picker :deep(.vpd-nav-btn) {
|
|
245
|
-
background: rgba(255, 255, 255, 0.2) !important;
|
|
246
|
-
color: white !important;
|
|
247
|
-
border-radius: 6px;
|
|
248
|
-
transition: all 0.2s ease;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
.shamsi-date-picker :deep(.vpd-nav-btn:hover) {
|
|
252
|
-
background: rgba(255, 255, 255, 0.3) !important;
|
|
253
|
-
transform: scale(1.05);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/* Calendar days */
|
|
257
|
-
.shamsi-date-picker :deep(.vpd-day) {
|
|
258
|
-
color: rgb(var(--v-theme-onSurface));
|
|
259
|
-
border-radius: 6px;
|
|
260
|
-
transition: all 0.2s ease;
|
|
261
|
-
font-weight: 500;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/* Ensure proper contrast for calendar days */
|
|
265
|
-
.shamsi-date-picker :deep(.vpd-day) {
|
|
266
|
-
color: rgb(var(--v-theme-onSurface)) !important;
|
|
267
|
-
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/* Force better visibility in dark mode */
|
|
271
|
-
.shamsi-date-picker :deep(.vpd-day) {
|
|
272
|
-
color: rgb(var(--v-theme-secondary)) !important;
|
|
273
|
-
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
.shamsi-date-picker :deep(.vpd-day:hover) {
|
|
277
|
-
background: rgb(var(--v-theme-primaryContainer)) !important;
|
|
278
|
-
color: rgb(var(--v-theme-onPrimaryContainer)) !important;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.shamsi-date-picker :deep(.vpd-day.vpd-selected) {
|
|
282
|
-
background: rgb(var(--v-theme-primary)) !important;
|
|
283
|
-
color: white !important;
|
|
284
|
-
box-shadow: 0 2px 8px rgba(var(--v-theme-primary), 0.3);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.shamsi-date-picker :deep(.vpd-day.vpd-today) {
|
|
288
|
-
border: 2px solid rgb(var(--v-theme-primary));
|
|
289
|
-
font-weight: bold;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/* Month/Year selector */
|
|
293
|
-
.shamsi-date-picker :deep(.vpd-month-year) {
|
|
294
|
-
color: white;
|
|
295
|
-
font-weight: 600;
|
|
296
|
-
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/* Weekday headers */
|
|
300
|
-
.shamsi-date-picker :deep(.vpd-weekday) {
|
|
301
|
-
color: rgb(var(--v-theme-primary));
|
|
302
|
-
font-weight: 600;
|
|
303
|
-
background: rgb(var(--v-theme-primaryContainer));
|
|
304
|
-
border-radius: 6px;
|
|
305
|
-
margin: 0px;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/* Footer buttons */
|
|
309
|
-
.shamsi-date-picker :deep(.vpd-actions button) {
|
|
310
|
-
background: rgb(var(--v-theme-secondary)) !important;
|
|
311
|
-
color: white !important;
|
|
312
|
-
border-radius: 8px;
|
|
313
|
-
font-weight: 500;
|
|
314
|
-
transition: all 0.2s ease;
|
|
315
|
-
border: none;
|
|
316
|
-
margin: 4px;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
.shamsi-date-picker :deep(.vpd-actions button:hover) {
|
|
320
|
-
background: rgb(var(--v-theme-primary)) !important;
|
|
321
|
-
transform: translateY(-1px);
|
|
322
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
.shamsi-date-picker :deep(.vpd-actions button:active) {
|
|
326
|
-
transform: translateY(0);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/* Responsive Design */
|
|
330
|
-
@media (max-width: 768px) {
|
|
331
|
-
.shamsi-date-picker :deep(.vpd-input-group) {
|
|
332
|
-
border-radius: 8px;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
.shamsi-date-picker :deep(.vpd-input-group input) {
|
|
336
|
-
padding: 10px 12px;
|
|
337
|
-
font-size: 14px;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
.shamsi-date-picker :deep(.vpd-icon-btn) {
|
|
341
|
-
padding: 6px;
|
|
342
|
-
margin: 2px;
|
|
343
|
-
min-width: 32px;
|
|
344
|
-
min-height: 32px;
|
|
345
|
-
display: flex;
|
|
346
|
-
align-items: center;
|
|
347
|
-
justify-content: center;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
.shamsi-date-picker :deep(.vpd-icon-btn i) {
|
|
351
|
-
font-size: 14px;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
.shamsi-date-picker :deep(.vpd-picker) {
|
|
355
|
-
max-width: 320px;
|
|
356
|
-
margin: 0 auto;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.shamsi-date-picker :deep(.vpd-day) {
|
|
360
|
-
padding: 8px 4px;
|
|
361
|
-
font-size: 14px;
|
|
362
|
-
min-width: 32px;
|
|
363
|
-
min-height: 32px;
|
|
364
|
-
display: flex;
|
|
365
|
-
align-items: center;
|
|
366
|
-
justify-content: center;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.shamsi-date-picker :deep(.vpd-weekday) {
|
|
370
|
-
padding: 6px 2px;
|
|
371
|
-
font-size: 12px;
|
|
372
|
-
min-width: 28px;
|
|
373
|
-
min-height: 28px;
|
|
374
|
-
display: flex;
|
|
375
|
-
align-items: center;
|
|
376
|
-
justify-content: center;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
.shamsi-date-picker :deep(.vpd-actions button) {
|
|
380
|
-
padding: 6px 12px;
|
|
381
|
-
font-size: 14px;
|
|
382
|
-
margin: 2px;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
.shamsi-date-picker :deep(.vpd-month-year) {
|
|
386
|
-
font-size: 16px;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
.shamsi-date-picker :deep(.vpd-nav-btn) {
|
|
390
|
-
padding: 4px;
|
|
391
|
-
min-width: 28px;
|
|
392
|
-
min-height: 28px;
|
|
393
|
-
display: flex;
|
|
394
|
-
align-items: center;
|
|
395
|
-
justify-content: center;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
@media (max-width: 480px) {
|
|
400
|
-
.shamsi-date-picker :deep(.vpd-picker) {
|
|
401
|
-
max-width: 280px;
|
|
402
|
-
border-radius: 8px;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
.shamsi-date-picker :deep(.vpd-day) {
|
|
406
|
-
padding: 6px 2px;
|
|
407
|
-
font-size: 12px;
|
|
408
|
-
min-width: 28px;
|
|
409
|
-
min-height: 28px;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
.shamsi-date-picker :deep(.vpd-weekday) {
|
|
413
|
-
padding: 4px 1px;
|
|
414
|
-
font-size: 11px;
|
|
415
|
-
min-width: 24px;
|
|
416
|
-
min-height: 24px;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
.shamsi-date-picker :deep(.vpd-actions button) {
|
|
420
|
-
padding: 4px 8px;
|
|
421
|
-
font-size: 12px;
|
|
422
|
-
margin: 1px;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
.shamsi-date-picker :deep(.vpd-month-year) {
|
|
426
|
-
font-size: 14px;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
.shamsi-date-picker :deep(.vpd-header) {
|
|
430
|
-
border-radius: 8px 8px 0 0;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/* Ensure proper touch targets on mobile */
|
|
435
|
-
@media (hover: none) and (pointer: coarse) {
|
|
436
|
-
.shamsi-date-picker :deep(.vpd-icon-btn),
|
|
437
|
-
.shamsi-date-picker :deep(.vpd-day),
|
|
438
|
-
.shamsi-date-picker :deep(.vpd-nav-btn),
|
|
439
|
-
.shamsi-date-picker :deep(.vpd-actions button) {
|
|
440
|
-
min-width: 44px;
|
|
441
|
-
min-height: 44px;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
</style>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = defineProps({
|
|
3
|
-
title: String
|
|
4
|
-
});
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<template>
|
|
8
|
-
<v-card variant="outlined">
|
|
9
|
-
<v-card-item class="py-3">
|
|
10
|
-
<v-card-title class="text-h5">{{ props.title }}</v-card-title>
|
|
11
|
-
</v-card-item>
|
|
12
|
-
<v-divider />
|
|
13
|
-
<v-card-text>
|
|
14
|
-
<slot />
|
|
15
|
-
</v-card-text>
|
|
16
|
-
</v-card>
|
|
17
|
-
</template>
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
const props = defineProps({
|
|
3
|
-
title: String
|
|
4
|
-
});
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
// ===============================|| Ui Parent Card||=============================== //
|
|
8
|
-
<template>
|
|
9
|
-
<v-card variant="flat">
|
|
10
|
-
<v-card-item>
|
|
11
|
-
<div class="d-sm-flex align-center justify-space-between">
|
|
12
|
-
<v-card-title>{{ props.title }}</v-card-title>
|
|
13
|
-
<slot name="action"></slot>
|
|
14
|
-
</div>
|
|
15
|
-
</v-card-item>
|
|
16
|
-
<v-divider></v-divider>
|
|
17
|
-
<v-card-text>
|
|
18
|
-
<slot />
|
|
19
|
-
</v-card-text>
|
|
20
|
-
</v-card>
|
|
21
|
-
</template>
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
<script lang="ts" setup>
|
|
2
|
-
import { computed, ref, watch, onMounted } from 'vue';
|
|
3
|
-
|
|
4
|
-
// Your Regex for thousand separator
|
|
5
|
-
const THOUSAND_SEPARATOR_REGEX = /\B(?=(\d{3})+(?!\d))/g;
|
|
6
|
-
|
|
7
|
-
// Helper functions (previously in formatters.ts)
|
|
8
|
-
const formatNumber = (value: string | number | undefined | null): string => {
|
|
9
|
-
if (value === undefined || value === null || value === '') return '';
|
|
10
|
-
const stringValue = value.toString().replace(/,/g, ''); // Remove existing commas
|
|
11
|
-
if (stringValue === '') return '';
|
|
12
|
-
return stringValue.replace(THOUSAND_SEPARATOR_REGEX, ',');
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const unformatNumber = (value: string | undefined | null): string => {
|
|
16
|
-
if (value === undefined || value === null) return '';
|
|
17
|
-
return value.toString().replace(/,/g, '');
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const props = defineProps<{
|
|
21
|
-
modelValue: string | number | undefined | null; // The raw, unformatted numeric string or number
|
|
22
|
-
label?: string;
|
|
23
|
-
placeholder?: string;
|
|
24
|
-
disabled?: boolean;
|
|
25
|
-
readonly?: boolean;
|
|
26
|
-
clearable?: boolean;
|
|
27
|
-
errorMessages?: string | string[];
|
|
28
|
-
min?: number; // For validation, not direct input blocking here
|
|
29
|
-
max?: number; // For validation
|
|
30
|
-
// Add any other v-text-field props you want to support
|
|
31
|
-
}>();
|
|
32
|
-
|
|
33
|
-
const emit = defineEmits<{
|
|
34
|
-
(e: 'update:modelValue', value: string): void;
|
|
35
|
-
(e: 'focus', event: FocusEvent): void;
|
|
36
|
-
(e: 'blur', event: FocusEvent): void;
|
|
37
|
-
}>();
|
|
38
|
-
|
|
39
|
-
// Internal ref to manage the displayed (formatted) value in the text field
|
|
40
|
-
const displayValue = ref('');
|
|
41
|
-
const isFocused = ref(false);
|
|
42
|
-
|
|
43
|
-
// When the underlying modelValue changes, update the displayValue (formatted)
|
|
44
|
-
watch(() => props.modelValue, (newModelValue) => {
|
|
45
|
-
if (!isFocused.value) {
|
|
46
|
-
displayValue.value = formatNumber(newModelValue);
|
|
47
|
-
} else {
|
|
48
|
-
// If focused, the display value should be unformatted for editing
|
|
49
|
-
// but ensure it syncs if modelValue changes externally while focused
|
|
50
|
-
const unformattedModel = unformatNumber(newModelValue !== null && newModelValue !== undefined ? newModelValue.toString() : '');
|
|
51
|
-
if (unformatNumber(displayValue.value) !== unformattedModel) {
|
|
52
|
-
displayValue.value = unformattedModel;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}, { immediate: true });
|
|
56
|
-
|
|
57
|
-
onMounted(() => {
|
|
58
|
-
displayValue.value = formatNumber(props.modelValue);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const handleInput = (event: Event) => {
|
|
62
|
-
const inputElement = event.target as HTMLInputElement;
|
|
63
|
-
let caretPosition = inputElement.selectionStart; // Store caret position
|
|
64
|
-
|
|
65
|
-
let rawValue = inputElement.value;
|
|
66
|
-
let unformatted = rawValue.replace(/[^\d]/g, ''); // Allow only digits
|
|
67
|
-
|
|
68
|
-
// Handle min/max (simplified: primarily for validation, not strict input blocking here)
|
|
69
|
-
if (props.min !== undefined && parseInt(unformatted, 10) < props.min) {
|
|
70
|
-
// unformatted = props.min.toString(); // Could clamp, but might be jarring.
|
|
71
|
-
}
|
|
72
|
-
if (props.max !== undefined && parseInt(unformatted, 10) > props.max) {
|
|
73
|
-
// unformatted = props.max.toString();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
emit('update:modelValue', unformatted); // Emit the raw unformatted value
|
|
77
|
-
|
|
78
|
-
// Update displayValue immediately with formatted version for the input field
|
|
79
|
-
// This can be tricky with cursor position.
|
|
80
|
-
const currentFormatted = formatNumber(unformatted);
|
|
81
|
-
|
|
82
|
-
// Calculate difference in length to adjust caret
|
|
83
|
-
const oldFormattedLength = displayValue.value.length;
|
|
84
|
-
const newFormattedLength = currentFormatted.length;
|
|
85
|
-
|
|
86
|
-
displayValue.value = currentFormatted; // Update internal display value
|
|
87
|
-
|
|
88
|
-
// Attempt to restore caret position
|
|
89
|
-
// This is a common challenge with formatted inputs.
|
|
90
|
-
// Vue nextTick is important here to wait for DOM update.
|
|
91
|
-
inputElement.value = currentFormatted; // Force update input element directly
|
|
92
|
-
if (caretPosition !== null) {
|
|
93
|
-
const diff = newFormattedLength - oldFormattedLength;
|
|
94
|
-
try {
|
|
95
|
-
inputElement.setSelectionRange(caretPosition + diff, caretPosition + diff);
|
|
96
|
-
} catch (e) {
|
|
97
|
-
// Some browsers might have issues if not fully visible or other edge cases
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const handleFocus = (event: FocusEvent) => {
|
|
103
|
-
isFocused.value = true;
|
|
104
|
-
displayValue.value = unformatNumber(props.modelValue !== null && props.modelValue !== undefined ? props.modelValue.toString() : ''); // Show raw number for editing
|
|
105
|
-
emit('focus', event);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const handleBlur = (event: FocusEvent) => {
|
|
109
|
-
isFocused.value = false;
|
|
110
|
-
displayValue.value = formatNumber(props.modelValue); // Format on blur
|
|
111
|
-
emit('blur', event);
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
</script>
|
|
115
|
-
|
|
116
|
-
<template>
|
|
117
|
-
<v-text-field
|
|
118
|
-
:model-value="displayValue"
|
|
119
|
-
:label="props.label"
|
|
120
|
-
:placeholder="props.placeholder"
|
|
121
|
-
:disabled="props.disabled"
|
|
122
|
-
:readonly="props.readonly"
|
|
123
|
-
:clearable="props.clearable"
|
|
124
|
-
:error-messages="props.errorMessages"
|
|
125
|
-
@input="handleInput"
|
|
126
|
-
@focus="handleFocus"
|
|
127
|
-
@blur="handleBlur"
|
|
128
|
-
inputmode="numeric"
|
|
129
|
-
pattern="[0-9,]*"
|
|
130
|
-
>
|
|
131
|
-
<!-- Pass through slots if needed -->
|
|
132
|
-
<template v-for="(_, slot) in $slots" #[slot]="scope">
|
|
133
|
-
<slot :name="slot" v-bind="scope || {}" />
|
|
134
|
-
</template>
|
|
135
|
-
</v-text-field>
|
|
136
|
-
</template>
|