@unsource/ui 2.1.5 → 2.2.0

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "unsource-ui",
3
3
  "configKey": "unsourceUi",
4
- "version": "2.1.5",
4
+ "version": "2.2.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -47,7 +47,10 @@ const module = defineNuxtModule({
47
47
  "nuxt-swiper": {},
48
48
  "@vueuse/nuxt": {},
49
49
  "@nuxtjs/i18n": {
50
- version: "^8.0.0"
50
+ version: "^10.0.0",
51
+ defaults: {
52
+ strategy: "no_prefix"
53
+ }
51
54
  }
52
55
  },
53
56
  // Default configuration options of the Nuxt module
@@ -63,7 +66,8 @@ const module = defineNuxtModule({
63
66
  "numeral",
64
67
  "persian-number",
65
68
  "ajv",
66
- "handlebars"
69
+ "handlebars",
70
+ "vue-json-pretty"
67
71
  ];
68
72
  }
69
73
  },
@@ -0,0 +1,34 @@
1
+ type Props = {
2
+ logo?: string;
3
+ head?: string;
4
+ type: 'login' | 'recover' | 'otp' | 'register';
5
+ userTypes?: Record<string, string>[];
6
+ loginType?: 'otp' | 'password';
7
+ mutiType?: boolean;
8
+ userParams?: Record<string, string | boolean>;
9
+ otpPage?: string;
10
+ redirectPage?: string;
11
+ profilePage?: string;
12
+ profileFormPage?: string;
13
+ loginPage?: string;
14
+ passLoginPage?: string;
15
+ successLoginAlert?: string;
16
+ title?: string;
17
+ buttonTitle?: string;
18
+ forgetPassword?: boolean;
19
+ click?: Record<string, never>;
20
+ shortHand?: boolean;
21
+ };
22
+ declare var __VLS_29: {};
23
+ type __VLS_Slots = {} & {
24
+ default?: (props: typeof __VLS_29) => any;
25
+ };
26
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
28
+ declare const _default: typeof __VLS_export;
29
+ export default _default;
30
+ type __VLS_WithSlots<T, S> = T & {
31
+ new (): {
32
+ $slots: S;
33
+ };
34
+ };
@@ -0,0 +1,326 @@
1
+ <template>
2
+ <div class="flex flex-col items-stretch gap-8 grow px-2 py-6 self-stretch">
3
+ <div class="grow-1 p-3 basis-50">
4
+ <div
5
+ v-if="logo"
6
+ class="flex flex-col items-center children:text-center gap-3 px-4 py-0"
7
+ >
8
+ <UnNuxtIcon
9
+ :name="logo"
10
+ class="!text-8xl text-primary-500"
11
+ />
12
+ </div>
13
+ <template v-if="['login', 'recover'].includes(type)">
14
+ <UnAuthInputs
15
+ v-model="form"
16
+ :type="type === 'recover' ? type : loginType"
17
+ :head
18
+ :have-tabs="true"
19
+ :login-page
20
+ :pass-login-page
21
+ :have-login-type="mutiType"
22
+ />
23
+ <div
24
+ v-if="type === 'login'"
25
+ class="flex items-center gap-2 mt-4"
26
+ >
27
+ <p class="text-(sm gray-600)">
28
+ با ورود،
29
+ <NuxtLink
30
+ to="https://parand.app/terms"
31
+ target="_blank"
32
+ class="text-gra-900 font-bold underline"
33
+ >قوانین و
34
+ مقررات
35
+ </NuxtLink>
36
+ استفاده از اپلیکیشن را میپذیرم
37
+ </p>
38
+ </div>
39
+ </template>
40
+ <div
41
+ v-else-if="type === 'otp'"
42
+ class="flex flex-col items-stretch gap-24"
43
+ >
44
+ <div class="flex flex-col items-stretch gap-6">
45
+ <div class="flex justify-between">
46
+ <p class="text-(gray-600 lg) font-semibold">
47
+ {{ $t("\u06A9\u062F \u062A\u0627\u06CC\u06CC\u062F \u0631\u0627 \u0648\u0627\u0631\u062F \u06A9\u0646\u06CC\u062F") }}
48
+ </p>
49
+ <div
50
+ class="text-xs text-gray-600 underline cursor-pointer"
51
+ @click="navigateTo({ name: 'login' })"
52
+ >
53
+ {{ $t("\u062A\u063A\u06CC\u06CC\u0631 \u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644 ") }}
54
+ </div>
55
+ </div>
56
+ <UnCodeInput
57
+ v-model="otp"
58
+ class="flex gap-1 self-center justify-between"
59
+ @complete="checkOTP"
60
+ />
61
+ <div class="flex justify-center items-center gap-2 text-gray-400 text-xs">
62
+ <p v-if="!isExpired">
63
+ {{ $t("\u0632\u0645\u0627\u0646 \u0628\u0627\u0642\u06CC\u200C\u0645\u0627\u0646\u062F\u0647: ") }}
64
+ </p>
65
+ <p
66
+ v-else
67
+ class="text-primary-500 cursor-pointer"
68
+ @click="sendAgain"
69
+ >
70
+ {{ $t("\u0627\u0631\u0633\u0627\u0644 \u0645\u062C\u062F\u062F") }}
71
+ </p>
72
+ <UnTimer
73
+ v-if="!isExpired"
74
+ :key="expiredAt"
75
+ v-model="isExpired"
76
+ :time="expiredAt"
77
+ />
78
+ </div>
79
+ </div>
80
+ <form>
81
+ <input
82
+ v-model="otp"
83
+ name="one-time-code"
84
+ class="w-0 h-0"
85
+ type="text"
86
+ autocomplete="one-time-code"
87
+ inputmode="numeric"
88
+ autofocus
89
+ pattern="\d{6}"
90
+ >
91
+ </form>
92
+ </div>
93
+ <slot />
94
+ </div>
95
+ <div class="flex flex-col gap-4 p-3 sticky bottom-2">
96
+ <template v-if="shortHand">
97
+ <UnAuthShortHand
98
+ v-if="forgetPassword"
99
+ :description="$t('\u062D\u0633\u0627\u0628 \u06A9\u0627\u0631\u0628\u0631\u06CC \u0646\u062F\u0627\u0631\u06CC\u062F\u061F ')"
100
+ :text-link="$t('\u062B\u0628\u062A \u0646\u0627\u0645 \u06A9\u0646\u06CC\u062F')"
101
+ link="/signup"
102
+ />
103
+ <UnAuthShortHand
104
+ v-else-if="otp"
105
+ :description="$t('\u0634\u0645\u0627\u0631\u0647 \u062A\u0644\u0641\u0646 \u0627\u0634\u062A\u0628\u0627\u0647 \u0627\u0633\u062A\u061F')"
106
+ :text-link="$t('\u0648\u06CC\u0631\u0627\u06CC\u0634')"
107
+ :link="`/login?type=${route.query.type || 'personal'}`"
108
+ />
109
+ <UnAuthShortHand
110
+ v-else
111
+ :description="$t('\u062D\u0633\u0627\u0628 \u06A9\u0627\u0631\u0628\u0631\u06CC \u062F\u0627\u0631\u06CC\u062F\u061F ')"
112
+ :text-link="$t('\u0648\u0627\u0631\u062F \u0634\u0648\u06CC\u062F')"
113
+ link="/login"
114
+ />
115
+ </template>
116
+ <UnButton
117
+ :loading="loading"
118
+ :label="buttonTitle || ButtonTitle"
119
+ :disable="disable"
120
+ variant="primary-fill"
121
+ @click="submit"
122
+ />
123
+ </div>
124
+ </div>
125
+ <UnLog :data="form" />
126
+ </template>
127
+
128
+ <script setup>
129
+ import {
130
+ computed,
131
+ navigateTo,
132
+ onMounted,
133
+ p2e,
134
+ ref,
135
+ useCookie,
136
+ useI18n,
137
+ useNuxtApp,
138
+ usePost,
139
+ useRoute,
140
+ useToken,
141
+ useUser,
142
+ useUserId
143
+ } from "#imports";
144
+ const { successLoginAlert = "\u062E\u0648\u0634 \u0622\u0645\u062F\u06CC\u062F", redirectPage = "index", profilePage = "profile", profileFormPage, otpPage = "login-otp", type, loginType = "password", userParams = {} } = defineProps({
145
+ logo: { type: String, required: false },
146
+ head: { type: String, required: false },
147
+ type: { type: String, required: true },
148
+ userTypes: { type: Array, required: false },
149
+ loginType: { type: String, required: false },
150
+ mutiType: { type: Boolean, required: false },
151
+ userParams: { type: Object, required: false },
152
+ otpPage: { type: String, required: false },
153
+ redirectPage: { type: String, required: false },
154
+ profilePage: { type: String, required: false },
155
+ profileFormPage: { type: String, required: false },
156
+ loginPage: { type: String, required: false },
157
+ passLoginPage: { type: String, required: false },
158
+ successLoginAlert: { type: String, required: false },
159
+ title: { type: String, required: false },
160
+ buttonTitle: { type: String, required: false },
161
+ forgetPassword: { type: Boolean, required: false },
162
+ click: { type: Object, required: false },
163
+ shortHand: { type: Boolean, required: false }
164
+ });
165
+ const route = useRoute();
166
+ const { $toast } = useNuxtApp();
167
+ const { t } = useI18n();
168
+ const loading = ref(false);
169
+ const phoneNumber = useCookie("phoneNumber");
170
+ const form = ref({});
171
+ const expiredAt = useCookie("expiredAt", {
172
+ maxAge: 365 * 24 * 60 * 60 * 1e3
173
+ });
174
+ const ButtonTitle = computed(
175
+ () => type === "login" && loginType == "otp" ? t("\u0627\u0631\u0633\u0627\u0644 \u06A9\u062F") : type === "login" && loginType == "password" ? t("\u0648\u0631\u0648\u062F") : type === "otp" ? t("\u062A\u0627\u06CC\u06CC\u062F") : type === "recover" ? t("\u062B\u0628\u062A") : type === "register" ? t("\u062B\u0628\u062A \u0646\u0627\u0645") : ""
176
+ );
177
+ const isValid = computed(() => form.value.phoneNumber && form.value.phoneNumber?.length === 11);
178
+ const loginByOtp = async () => {
179
+ if (!isValid.value || loading.value) return;
180
+ loading.value = true;
181
+ const { result } = await usePost("/login-by-phone-otp", {
182
+ phoneNumber: p2e(form.value.phoneNumber)
183
+ // template: template[config.userType]
184
+ });
185
+ if (result) {
186
+ expiredAt.value = result.expiredAt;
187
+ phoneNumber.value = p2e(form.value.phoneNumber);
188
+ await navigateTo({ name: otpPage, query: route.query });
189
+ }
190
+ loading.value = false;
191
+ };
192
+ const otp = ref("");
193
+ const token = useToken();
194
+ const userId = useUserId();
195
+ if (["login", "register"].includes(type) && token.value && userId.value) {
196
+ navigateTo({ name: redirectPage });
197
+ }
198
+ const user = useUser();
199
+ const isExpired = ref(false);
200
+ const disable = computed(
201
+ () => type === "login" && loginType == "otp" ? !form.value?.phoneNumber : type === "login" && loginType == "password" ? !form.value?.phoneNumber || !form.value?.password : type === "otp" ? otp.value?.length < 6 : type === "recover" ? !form.value?.password || !form.value?.confirmedPassword || form.value?.password !== form.value?.confirmedPassword : type === "register" ? !form.value?.phoneNumber || !form.value?.password : false
202
+ );
203
+ let ac;
204
+ const getOtpFromPhone = async () => {
205
+ if (ac) {
206
+ ac.abort();
207
+ }
208
+ ac = new AbortController();
209
+ if ("OTPCredential" in window) {
210
+ navigator.credentials.get({
211
+ otp: { transport: ["sms"] },
212
+ signal: ac.signal
213
+ }).then((e) => {
214
+ otp.value = e.code;
215
+ checkOTP(otp.value);
216
+ });
217
+ }
218
+ };
219
+ const checkOTP = async (code = "") => {
220
+ if (loading.value) return;
221
+ loading.value = true;
222
+ const { result } = await usePost("/get-token-by-otp", { phoneNumber: phoneNumber.value, code: code || otp.value }, {
223
+ params: {
224
+ "with-profile": true,
225
+ ...userParams
226
+ },
227
+ headers: {
228
+ "no-error": true
229
+ }
230
+ });
231
+ if (result) {
232
+ token.value = result.token.type + " " + result.token.token;
233
+ userId.value = result.user.id;
234
+ user.value = result.user;
235
+ if (result.user.profile || !profileFormPage) {
236
+ navigateTo({ name: profilePage });
237
+ } else {
238
+ navigateTo({ name: profileFormPage || "profile-form" });
239
+ }
240
+ $toast.success(successLoginAlert);
241
+ } else {
242
+ $toast.success(t("\u06A9\u062F \u0648\u0627\u0631\u062F \u0634\u062F\u0647 \u0635\u062D\u06CC\u062D \u0646\u0645\u06CC\u0628\u0627\u0634\u062F."));
243
+ loading.value = false;
244
+ }
245
+ };
246
+ const sendAgain = async () => {
247
+ if (loading.value) return;
248
+ loading.value = true;
249
+ const { result } = await usePost("/login-by-phone-otp", {
250
+ phoneNumber: phoneNumber.value
251
+ });
252
+ if (result) {
253
+ getOtpFromPhone();
254
+ expiredAt.value = result.expiredAt;
255
+ isExpired.value = false;
256
+ $toast.success("\u06A9\u062F \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u0627\u0631\u0633\u0627\u0644 \u0634\u062F");
257
+ }
258
+ loading.value = false;
259
+ };
260
+ const setPassword = async () => {
261
+ if (loading.value) return;
262
+ loading.value = true;
263
+ const { result } = await usePost("/set-pass", {
264
+ password: form.value.password
265
+ }, {
266
+ headers: {
267
+ "no-error": true
268
+ }
269
+ });
270
+ if (result) {
271
+ $toast.success("\u0631\u0645\u0632 \u0639\u0628\u0648\u0631 \u0628\u0627 \u0645\u0648\u0641\u0642\u06CC\u062A \u062A\u063A\u06CC\u06CC\u0631 \u06CC\u0627\u0641\u062A");
272
+ navigateTo({ name: "profile" });
273
+ } else {
274
+ $toast.success("\u0631\u0645\u0632 \u0628\u0627\u06CC\u062F \u062D\u062F\u0627\u0642\u0644 8 \u06A9\u0627\u0631\u0627\u06A9\u062A\u0631 \u0628\u0627\u0634\u062F.");
275
+ loading.value = false;
276
+ }
277
+ loading.value = false;
278
+ };
279
+ const loginByPass = async () => {
280
+ if (loading.value) return;
281
+ loading.value = true;
282
+ const { result } = await usePost("/login-by-pass", {
283
+ phoneNumber: p2e(form.value.phoneNumber),
284
+ password: form.value.password
285
+ }, {
286
+ params: {
287
+ "with-profile": true,
288
+ ...userParams
289
+ },
290
+ headers: {
291
+ "no-error": true
292
+ }
293
+ });
294
+ if (result) {
295
+ token.value = result.token.type + " " + result.token.token;
296
+ userId.value = result.user.id;
297
+ user.value = result.user;
298
+ if (result.user.profile || !profileFormPage) {
299
+ navigateTo({ name: profilePage });
300
+ } else {
301
+ navigateTo({ name: profileFormPage || "profile-form" });
302
+ }
303
+ $toast.success(successLoginAlert);
304
+ } else {
305
+ $toast.error("\u0627\u0637\u0644\u0627\u0639\u0627\u062A \u0648\u0627\u0631\u062F \u0634\u062F\u0647 \u0635\u062D\u06CC\u062D \u0646\u0645\u06CC\u0628\u0627\u0634\u062F.");
306
+ loading.value = false;
307
+ }
308
+ };
309
+ const submit = async () => {
310
+ if (type === "login" && loginType === "otp") {
311
+ return loginByOtp();
312
+ }
313
+ if (type === "login" && loginType === "password") {
314
+ return loginByPass();
315
+ }
316
+ if (type === "recover") {
317
+ return setPassword();
318
+ }
319
+ if (type === "otp") {
320
+ return checkOTP();
321
+ }
322
+ };
323
+ onMounted(() => {
324
+ getOtpFromPhone();
325
+ });
326
+ </script>
@@ -0,0 +1,34 @@
1
+ type Props = {
2
+ logo?: string;
3
+ head?: string;
4
+ type: 'login' | 'recover' | 'otp' | 'register';
5
+ userTypes?: Record<string, string>[];
6
+ loginType?: 'otp' | 'password';
7
+ mutiType?: boolean;
8
+ userParams?: Record<string, string | boolean>;
9
+ otpPage?: string;
10
+ redirectPage?: string;
11
+ profilePage?: string;
12
+ profileFormPage?: string;
13
+ loginPage?: string;
14
+ passLoginPage?: string;
15
+ successLoginAlert?: string;
16
+ title?: string;
17
+ buttonTitle?: string;
18
+ forgetPassword?: boolean;
19
+ click?: Record<string, never>;
20
+ shortHand?: boolean;
21
+ };
22
+ declare var __VLS_29: {};
23
+ type __VLS_Slots = {} & {
24
+ default?: (props: typeof __VLS_29) => any;
25
+ };
26
+ declare const __VLS_base: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
27
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
28
+ declare const _default: typeof __VLS_export;
29
+ export default _default;
30
+ type __VLS_WithSlots<T, S> = T & {
31
+ new (): {
32
+ $slots: S;
33
+ };
34
+ };
@@ -0,0 +1,23 @@
1
+ import type { TabItem } from './UnTab.vue.js';
2
+ type __VLS_Props = {
3
+ type?: 'recover' | 'otp' | 'password';
4
+ userTypes?: TabItem[];
5
+ head?: string;
6
+ description?: string;
7
+ haveLoginType?: boolean;
8
+ forgetPass?: boolean;
9
+ loginPage?: string;
10
+ passLoginPage?: string;
11
+ forgetPage?: string;
12
+ };
13
+ type __VLS_ModelProps = {
14
+ modelValue: Record<string, any>;
15
+ };
16
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
17
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ "update:modelValue": (value: Record<string, any>) => any;
19
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
20
+ "onUpdate:modelValue"?: ((value: Record<string, any>) => any) | undefined;
21
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
@@ -0,0 +1,86 @@
1
+ <template>
2
+ <div class="flex flex-col items-stretch gap-6">
3
+ <div class="flex justify-between items-center">
4
+ <p class="text-(gray-600 2xl) font-semibold">
5
+ {{ head }}
6
+ </p>
7
+ <NuxtLink
8
+ v-if="haveLoginType"
9
+ :to="{ name: type === 'password' ? loginPage : passLoginPage, query: { role: route.query.role } }"
10
+ class="text-xs text-primary-500 underline cursor-pointer"
11
+ >
12
+ {{ type === "password" ? $t("\u0648\u0631\u0648\u062F \u0628\u0627 \u06A9\u062F \u06CC\u06A9\u0628\u0627\u0631 \u0645\u0635\u0631\u0641") : $t("\u0648\u0631\u0648\u062F \u0628\u0627 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631") }}
13
+ </NuxtLink>
14
+ </div>
15
+ <p
16
+ v-if="description"
17
+ class="text-(gray-600 base)"
18
+ >
19
+ {{ description }}
20
+ </p>
21
+ <UnTab
22
+ v-if="userTypes?.length"
23
+ route-target="query"
24
+ routable
25
+ mini
26
+ :items="userTypes"
27
+ class="self-start"
28
+ />
29
+ <UnNormalInput
30
+ v-if="type !== 'recover'"
31
+ v-model="modelValue.phoneNumber"
32
+ :placeholder="$t('\u0634\u0645\u0627\u0631\u0647 \u0645\u0648\u0628\u0627\u06CC\u0644')"
33
+ input-mode="numeric"
34
+ />
35
+ <template v-if="haveLoginType && type === 'password'">
36
+ <UnNormalInput
37
+ v-model="modelValue.password"
38
+ :placeholder="$t('\u0631\u0645\u0632 \u0639\u0628\u0648\u0631')"
39
+ input-type="password"
40
+ :password="true"
41
+ />
42
+ <NuxtLink
43
+ v-if="forgetPass"
44
+ :to="{ name: forgetPage }"
45
+ class="text-sm text-gray-400 underline cursor-pointer flex justify-center items-center"
46
+ >
47
+ {{ $t("\u0641\u0631\u0627\u0645\u0648\u0634\u06CC \u0631\u0645\u0632 \u0639\u0628\u0648\u0631") }}
48
+ </NuxtLink>
49
+ </template>
50
+ <template v-if="type === 'recover'">
51
+ <UnNormalInput
52
+ v-model="modelValue.password"
53
+ :placeholder="$t('\u0631\u0645\u0632 \u0639\u0628\u0648\u0631')"
54
+ input-type="password"
55
+ :password="true"
56
+ />
57
+ <UnNormalInput
58
+ v-model="modelValue.confirmedPassword"
59
+ :placeholder="$t('\u062A\u06A9\u0631\u0627\u0631 \u0631\u0645\u0632 \u0639\u0628\u0648\u0631')"
60
+ input-type="password"
61
+ :password="true"
62
+ />
63
+ </template>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup>
68
+ import { useRoute } from "#imports";
69
+ const route = useRoute();
70
+ const {
71
+ forgetPage = "forget-password",
72
+ loginPage = "login",
73
+ passLoginPage = "login-pass"
74
+ } = defineProps({
75
+ type: { type: String, required: false },
76
+ userTypes: { type: Array, required: false },
77
+ head: { type: String, required: false },
78
+ description: { type: String, required: false },
79
+ haveLoginType: { type: Boolean, required: false },
80
+ forgetPass: { type: Boolean, required: false },
81
+ loginPage: { type: String, required: false },
82
+ passLoginPage: { type: String, required: false },
83
+ forgetPage: { type: String, required: false }
84
+ });
85
+ const modelValue = defineModel({ type: Object, ...{ required: true } });
86
+ </script>
@@ -0,0 +1,23 @@
1
+ import type { TabItem } from './UnTab.vue.js';
2
+ type __VLS_Props = {
3
+ type?: 'recover' | 'otp' | 'password';
4
+ userTypes?: TabItem[];
5
+ head?: string;
6
+ description?: string;
7
+ haveLoginType?: boolean;
8
+ forgetPass?: boolean;
9
+ loginPage?: string;
10
+ passLoginPage?: string;
11
+ forgetPage?: string;
12
+ };
13
+ type __VLS_ModelProps = {
14
+ modelValue: Record<string, any>;
15
+ };
16
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
17
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
18
+ "update:modelValue": (value: Record<string, any>) => any;
19
+ }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
20
+ "onUpdate:modelValue"?: ((value: Record<string, any>) => any) | undefined;
21
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
22
+ declare const _default: typeof __VLS_export;
23
+ export default _default;
@@ -0,0 +1,8 @@
1
+ type __VLS_Props = {
2
+ link?: string;
3
+ textLink: string;
4
+ description?: string;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,19 @@
1
+ <template>
2
+ <p class="text-(xs text) font-extrabold gap-1">
3
+ {{ description }}
4
+ <NuxtLink
5
+ :to="link || '#'"
6
+ class="text-primary-500"
7
+ >
8
+ {{ textLink }}
9
+ </NuxtLink>
10
+ </p>
11
+ </template>
12
+
13
+ <script setup>
14
+ defineProps({
15
+ link: { type: String, required: false },
16
+ textLink: { type: String, required: true },
17
+ description: { type: String, required: false }
18
+ });
19
+ </script>
@@ -0,0 +1,8 @@
1
+ type __VLS_Props = {
2
+ link?: string;
3
+ textLink: string;
4
+ description?: string;
5
+ };
6
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
7
+ declare const _default: typeof __VLS_export;
8
+ export default _default;
@@ -0,0 +1,6 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {
4
+ $emit: typeof emit;
5
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const emit: (event: "complete" | "change", ...args: any[]) => void;
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <v-otp-input
3
+ id="code-input"
4
+ ref="otpInput"
5
+ :value="value"
6
+ dir="ltr"
7
+ input-classes="otp-input"
8
+ separator=""
9
+ :num-inputs="6"
10
+ :should-auto-focus="true"
11
+ :is-input-num="true"
12
+ @on-change="onChange"
13
+ @on-complete="emit('complete', $event)"
14
+ />
15
+ </template>
16
+
17
+ <script setup>
18
+ import VOtpInput from "vue3-otp-input";
19
+ const emit = defineEmits(["complete", "change"]);
20
+ const value = defineModel();
21
+ const onChange = ($event) => {
22
+ value.value = $event;
23
+ emit("change");
24
+ };
25
+ </script>
26
+
27
+ <style>
28
+ #code-input .otp-input {
29
+ @apply w-15 h-15 bg-white b-rd-2 text-center gap-2 <md:(w-12 h-12);
30
+ }
31
+ </style>
@@ -0,0 +1,6 @@
1
+ declare const _default: typeof __VLS_export;
2
+ export default _default;
3
+ declare const __VLS_export: import("vue").DefineComponent<{}, {
4
+ $emit: typeof emit;
5
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
6
+ declare const emit: (event: "complete" | "change", ...args: any[]) => void;
@@ -1,12 +1,12 @@
1
1
  import type { Input } from '../types/models.js';
2
2
  type __VLS_Props = {
3
3
  disabled?: boolean;
4
- Input?: Input;
4
+ Input?: Partial<Input>;
5
5
  Type?: Input['type'];
6
6
  isError?: boolean;
7
7
  index?: number;
8
8
  };
9
- declare const Input: Input | undefined;
9
+ declare const Input: Partial<Input> | undefined;
10
10
  type __VLS_ModelProps = {
11
11
  modelValue?: any;
12
12
  };
@@ -1,12 +1,12 @@
1
1
  import type { Input } from '../types/models.js';
2
2
  type __VLS_Props = {
3
3
  disabled?: boolean;
4
- Input?: Input;
4
+ Input?: Partial<Input>;
5
5
  Type?: Input['type'];
6
6
  isError?: boolean;
7
7
  index?: number;
8
8
  };
9
- declare const Input: Input | undefined;
9
+ declare const Input: Partial<Input> | undefined;
10
10
  type __VLS_ModelProps = {
11
11
  modelValue?: any;
12
12
  };
@@ -15,6 +15,8 @@
15
15
  </template>
16
16
 
17
17
  <script setup>
18
+ import VueJsonPretty from "vue-json-pretty";
19
+ import "vue-json-pretty/lib/styles.css";
18
20
  defineProps({
19
21
  data: {
20
22
  type: [Number, Object, Array, String, Boolean],
@@ -0,0 +1,51 @@
1
+ interface Props {
2
+ className?: string;
3
+ valueClassName?: string;
4
+ focusClassName?: string;
5
+ labelClass?: string;
6
+ prependIcon?: string;
7
+ prependIconType?: string;
8
+ appendIcon?: string;
9
+ appendIconType?: string;
10
+ appendIconClass?: string;
11
+ appendText?: string;
12
+ inputType?: string;
13
+ placeholder?: string;
14
+ label?: string;
15
+ password?: boolean;
16
+ date?: boolean;
17
+ disabled?: boolean;
18
+ inputMode?: string;
19
+ iconColor?: string;
20
+ bgStyle?: string;
21
+ handler?: any;
22
+ focusable?: boolean;
23
+ }
24
+ type __VLS_Props = Props;
25
+ type __VLS_ModelProps = {
26
+ modelValue?: any;
27
+ };
28
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
29
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{}>, {
30
+ date: boolean;
31
+ password: boolean;
32
+ appendIcon: string;
33
+ label: string;
34
+ inputType: string;
35
+ placeholder: string;
36
+ disabled: boolean;
37
+ focusable: boolean;
38
+ className: string;
39
+ valueClassName: string;
40
+ focusClassName: string;
41
+ labelClass: string;
42
+ prependIcon: string;
43
+ appendIconType: string;
44
+ appendIconClass: string;
45
+ appendText: string;
46
+ inputMode: string;
47
+ iconColor: string;
48
+ bgStyle: string;
49
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
50
+ declare const _default: typeof __VLS_export;
51
+ export default _default;
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="flex flex-col gap-1.5 ">
3
+ <p
4
+ v-if="label"
5
+ :class="labelClass"
6
+ >
7
+ {{ label }}
8
+ </p>
9
+ <div
10
+ v-on-click-outside="() => focused = false"
11
+ class="flex relative px-3 py-1 gap-1 h-12 items-center bg-white"
12
+ :class="[value && !focused ? valueClassName : focused ? focusClassName : bgStyle, className]"
13
+ >
14
+ <UnNuxtIcon
15
+ v-if="prependIcon"
16
+ :name="prependIcon"
17
+ :icon-type="prependIconType"
18
+ :class="[iconColor ? iconColor : 'text-gray-400']"
19
+ />
20
+ <UnIRDatePicker
21
+ v-if="date"
22
+ v-model="value"
23
+ format="YYYY-MM-DD[T]HH:mm:ssZ"
24
+ class="text-text"
25
+ display-format="jDD jMMMM jYYYY"
26
+ :placeholder="placeholder"
27
+ />
28
+ <input
29
+ v-if="InputType !== 'textarea'"
30
+ v-model="value"
31
+ dir="rtl"
32
+ :type="InputType"
33
+ :inputmode="inputMode"
34
+ class="flex-grow bg-white placeholder-gray-200 text-text-head font-300 text-sm"
35
+ :disabled="disabled"
36
+ :placeholder="!focused ? placeholder : value || ''"
37
+ @focus="date ? InputType = 'date' : focused = true"
38
+ >
39
+ <textarea
40
+ v-else
41
+ v-model="value"
42
+ :placeholder="placeholder"
43
+ :disabled="disabled"
44
+ class="border-none text-sm font-400 grow c-gray-900 placeholder:(c-gray-400) outline-none bg-white h-24"
45
+ @focus="date ? InputType = 'date' : ''"
46
+ @blur="date ? InputType = 'text' : ''"
47
+ />
48
+ <UnNuxtIcon
49
+ v-if="password"
50
+ :name="InputType === 'text' ? 'eye-slash' : 'eye'"
51
+ icon-type="svg"
52
+ class="!text-gray-200 cursor-pointer"
53
+ @click="InputType = InputType === 'text' ? 'password' : 'text'"
54
+ />
55
+ <UnNuxtIcon
56
+ v-if="appendIcon"
57
+ :name="appendIcon"
58
+ :icon-type="appendIconType"
59
+ :class="[iconColor ? iconColor : 'text-gray-400', appendIconClass]"
60
+ class="!svg:(w-3 h-3) bg-bg bg-opacity-30 justify-center rounded-full"
61
+ @click="$emit('append')"
62
+ />
63
+ <p
64
+ v-if="appendText"
65
+ dir="ltr"
66
+ class="font-400 text-xs text-text-head whitespace-nowrap"
67
+ >
68
+ {{ appendText }}
69
+ </p>
70
+ </div>
71
+ </div>
72
+ </template>
73
+
74
+ <script setup>
75
+ import { vOnClickOutside } from "@vueuse/components";
76
+ import { ref } from "#imports";
77
+ const props = defineProps({
78
+ className: { type: String, required: false, default: "rounded-2xl bg-bg" },
79
+ valueClassName: { type: String, required: false, default: "border-(1 solid gray-200) bg-bg" },
80
+ focusClassName: { type: String, required: false, default: "border-(2 solid primary-500) !bg-bg" },
81
+ labelClass: { type: String, required: false, default: "text-(xs text-head) font-400 leading-6" },
82
+ prependIcon: { type: String, required: false, default: "" },
83
+ prependIconType: { type: String, required: false },
84
+ appendIcon: { type: String, required: false, default: "" },
85
+ appendIconType: { type: String, required: false, default: "svg" },
86
+ appendIconClass: { type: String, required: false, default: "" },
87
+ appendText: { type: String, required: false, default: "" },
88
+ inputType: { type: String, required: false, default: "text" },
89
+ placeholder: { type: String, required: false, default: "" },
90
+ label: { type: String, required: false, default: "" },
91
+ password: { type: Boolean, required: false, default: false },
92
+ date: { type: Boolean, required: false, default: false },
93
+ disabled: { type: Boolean, required: false, default: false },
94
+ inputMode: { type: String, required: false, default: "" },
95
+ iconColor: { type: String, required: false, default: "" },
96
+ bgStyle: { type: String, required: false, default: "bg-bg border-(1 solid gray-200)" },
97
+ handler: { type: null, required: false },
98
+ focusable: { type: Boolean, required: false, default: false }
99
+ });
100
+ defineEmits(["append", "update:modelValue"]);
101
+ const value = defineModel();
102
+ const focused = ref(false);
103
+ const InputType = ref(props.inputType);
104
+ </script>
105
+
106
+ <style>
107
+ input {
108
+ outline: none;
109
+ }
110
+ </style>
@@ -0,0 +1,51 @@
1
+ interface Props {
2
+ className?: string;
3
+ valueClassName?: string;
4
+ focusClassName?: string;
5
+ labelClass?: string;
6
+ prependIcon?: string;
7
+ prependIconType?: string;
8
+ appendIcon?: string;
9
+ appendIconType?: string;
10
+ appendIconClass?: string;
11
+ appendText?: string;
12
+ inputType?: string;
13
+ placeholder?: string;
14
+ label?: string;
15
+ password?: boolean;
16
+ date?: boolean;
17
+ disabled?: boolean;
18
+ inputMode?: string;
19
+ iconColor?: string;
20
+ bgStyle?: string;
21
+ handler?: any;
22
+ focusable?: boolean;
23
+ }
24
+ type __VLS_Props = Props;
25
+ type __VLS_ModelProps = {
26
+ modelValue?: any;
27
+ };
28
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
29
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{}>, {
30
+ date: boolean;
31
+ password: boolean;
32
+ appendIcon: string;
33
+ label: string;
34
+ inputType: string;
35
+ placeholder: string;
36
+ disabled: boolean;
37
+ focusable: boolean;
38
+ className: string;
39
+ valueClassName: string;
40
+ focusClassName: string;
41
+ labelClass: string;
42
+ prependIcon: string;
43
+ appendIconType: string;
44
+ appendIconClass: string;
45
+ appendText: string;
46
+ inputMode: string;
47
+ iconColor: string;
48
+ bgStyle: string;
49
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
50
+ declare const _default: typeof __VLS_export;
51
+ export default _default;
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ time: string;
3
+ };
4
+ type __VLS_ModelProps = {
5
+ modelValue?: any;
6
+ };
7
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
8
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
9
+ timestamp: import("vue").ShallowRef<number>;
10
+ pause: import("@vueuse/shared").Fn;
11
+ resume: import("@vueuse/shared").Fn;
12
+ diff: import("vue").ComputedRef<number>;
13
+ isExpired: import("vue").ComputedRef<boolean>;
14
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
@@ -0,0 +1,31 @@
1
+ <template>
2
+ <time
3
+ dir="ltr"
4
+ class="text-center font-black text-base text-primary-500 "
5
+ >
6
+ {{ diff > d ? Math.floor(diff / d) + ":" : "" }}
7
+ {{ diff > h ? Math.floor(diff % d / h) + ":" : "" }}
8
+ {{ diff > m ? Math.floor(diff % h / m) + ":" : "" }}
9
+ {{ Math.floor(diff % m) }}
10
+ </time>
11
+ </template>
12
+
13
+ <script setup>
14
+ import { computed, moment, useTimestamp, watch } from "#imports";
15
+ const props = defineProps({
16
+ time: { type: String, required: true }
17
+ });
18
+ const m = 60;
19
+ const h = 60 * m;
20
+ const d = 24 * h;
21
+ defineEmits(["complete"]);
22
+ const value = defineModel();
23
+ const { timestamp, pause, resume } = useTimestamp({ controls: true, interval: 330 });
24
+ const diff = computed(() => (moment(props.time).valueOf() - timestamp.value) / 1e3);
25
+ const isExpired = computed(() => diff.value <= 0);
26
+ value.value = isExpired.value;
27
+ watch(isExpired, () => {
28
+ value.value = isExpired.value;
29
+ });
30
+ defineExpose({ timestamp, pause, resume, diff, isExpired });
31
+ </script>
@@ -0,0 +1,16 @@
1
+ type __VLS_Props = {
2
+ time: string;
3
+ };
4
+ type __VLS_ModelProps = {
5
+ modelValue?: any;
6
+ };
7
+ type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
8
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
9
+ timestamp: import("vue").ShallowRef<number>;
10
+ pause: import("@vueuse/shared").Fn;
11
+ resume: import("@vueuse/shared").Fn;
12
+ diff: import("vue").ComputedRef<number>;
13
+ isExpired: import("vue").ComputedRef<boolean>;
14
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
15
+ declare const _default: typeof __VLS_export;
16
+ export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unsource/ui",
3
- "version": "2.1.5",
3
+ "version": "2.2.0",
4
4
  "private": false,
5
5
  "description": "nuxt ui kit for unsource env",
6
6
  "repository": "https://github.com/alisa2142/unsource-ui",
@@ -36,9 +36,9 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@neshan-maps-platform/vue3-openlayers": "^2.0.1",
39
- "@nuxt/kit": "^4.2.0",
39
+ "@nuxt/kit": "^3.20.0",
40
40
  "@nuxtjs/device": "^3.2.4",
41
- "@nuxtjs/i18n": "^8.5.6",
41
+ "@nuxtjs/i18n": "^10.1.2",
42
42
  "@persian-tools/persian-tools": "^4.0.4",
43
43
  "@types/big.js": "^6.2.2",
44
44
  "@types/numeral": "^2.0.5",
@@ -57,6 +57,8 @@
57
57
  "socket.io-client": "^4.8.1",
58
58
  "swiper": "^11.2.10",
59
59
  "unocss-preset-scrollbar": "^3.2.0",
60
+ "vue-json-pretty": "^2.6.0",
61
+ "vue3-otp-input": "^0.5.40",
60
62
  "vue3-persian-datetime-picker": "^1.2.2",
61
63
  "vue3-toastify": "^0.2.8"
62
64
  },
@@ -81,13 +83,12 @@
81
83
  "@nuxt/module-builder": "^1.0.2",
82
84
  "@nuxt/schema": "^3.19.3",
83
85
  "@nuxt/test-utils": "^3.19.2",
84
- "@nuxt/vite-builder": "~3.15.4",
85
86
  "@types/node": "latest",
86
87
  "@unhead/vue": "^1.11.20",
87
88
  "@unocss/nuxt": "^66.5.3",
88
89
  "changelogen": "^0.6.2",
89
90
  "eslint": "^9.37.0",
90
- "nuxt": "^3.19.3",
91
+ "nuxt": "^3.20.0",
91
92
  "sass": "^1.93.2",
92
93
  "sass-embedded": "^1.93.2",
93
94
  "typescript": "~5.9.3",