adata-ui 2.1.40-beta → 2.1.40-beta.10

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.
Files changed (50) hide show
  1. package/components/elements/a-select-row/ASelectRowV2.vue +214 -0
  2. package/components/elements/button/AButtonV2.vue +112 -0
  3. package/components/elements/leave-note/ALeaveNote.vue +38 -17
  4. package/components/elements/segmented/ASegmentedV2.vue +58 -0
  5. package/components/elements/select/ASelectV2.vue +589 -0
  6. package/components/elements/show-more/AShowMoreV2.vue +26 -0
  7. package/components/elements/star-rating/AStarRating.vue +12 -4
  8. package/components/elements/status-badge-v2/StatusBadgeV2.vue +78 -0
  9. package/components/features/pk-mobile-services/APkMobileServices.vue +5 -27
  10. package/components/forms/checkbox/ACheckboxV2.vue +229 -0
  11. package/components/forms/feedback-form/FeedbackForm.vue +8 -8
  12. package/components/forms/input/AInputV2.vue +542 -0
  13. package/components/forms/input/textarea/ATextareaV2.vue +248 -0
  14. package/components/forms/toggle/AToggleV2.vue +71 -0
  15. package/components/modals/AnotherDeviceModal.vue +22 -18
  16. package/components/modals/ApplicationAcceptedModal.vue +12 -15
  17. package/components/modals/ConnectingTariffModal.vue +13 -20
  18. package/components/modals/Insufficient-funds-modal.vue +18 -33
  19. package/components/modals/LimitReachedModal.vue +4 -3
  20. package/components/modals/NoAccessModal.vue +9 -11
  21. package/components/modals/PaymentMethodModal.vue +1 -1
  22. package/components/modals/ReportBugConfirmModal.vue +12 -10
  23. package/components/modals/ReportBugModal.vue +42 -36
  24. package/components/modals/Resend.vue +9 -10
  25. package/components/modals/SubmitApplicationModal.vue +27 -24
  26. package/components/modals/id/IdConfirmAccountOtpModal.vue +4 -9
  27. package/components/modals/id/IdLoginModal.vue +3 -8
  28. package/components/modals/id/IdModals.vue +23 -10
  29. package/components/modals/id/IdTwoFactorModal.vue +3 -8
  30. package/components/navigation/header/AHeader.vue +5 -5
  31. package/components/navigation/header/HeaderLink.vue +15 -21
  32. package/components/navigation/header/NavList.vue +18 -62
  33. package/components/navigation/header/ProductMenu.vue +55 -47
  34. package/components/navigation/pill-tabs/APillTabsV2.vue +118 -0
  35. package/components/overlays/modal/AModalV2.vue +388 -0
  36. package/composables/useAccessTokenCookie.ts +25 -0
  37. package/composables/useActiveNavigation.ts +84 -0
  38. package/composables/useChipOverflow.ts +92 -0
  39. package/composables/useHeaderNavigationLinks.ts +53 -23
  40. package/icons/arrow/arrow-right.vue +14 -0
  41. package/icons/briefcase.vue +14 -0
  42. package/icons/car-side.vue +16 -0
  43. package/icons/cart.vue +15 -0
  44. package/icons/download-rounded.vue +15 -0
  45. package/icons/shield-verified.vue +14 -0
  46. package/lang/en.ts +34 -4
  47. package/lang/kk.ts +35 -5
  48. package/lang/ru.ts +36 -6
  49. package/package.json +1 -1
  50. package/shared/constans/pages.ts +8 -2
@@ -0,0 +1,78 @@
1
+ <script lang="ts" setup>
2
+ import { twMerge } from 'tailwind-merge'
3
+
4
+ defineOptions({ name: 'StatusBadgeV2', inheritAttrs: false })
5
+
6
+ type BadgeType = 'primary' | 'success' | 'danger' | 'gray' | 'orange' | 'warning'
7
+ type BadgeView = 'default' | 'inverted' | 'transparent'
8
+ type BadgeSize = 'xs' | 'sm' | 'md' | 'lg'
9
+
10
+ interface Props {
11
+ type?: BadgeType
12
+ view?: BadgeView
13
+ size?: BadgeSize
14
+ }
15
+
16
+ const props = withDefaults(defineProps<Props>(), {
17
+ type: 'primary',
18
+ view: 'inverted',
19
+ size: 'sm',
20
+ })
21
+
22
+ const base
23
+ = 'inline-flex w-fit items-center justify-center gap-1.5 rounded-full font-semibold select-none'
24
+
25
+ const sizeClasses: Record<BadgeSize, string> = {
26
+ xs: 'px-2 py-0.5 text-[11px] leading-none',
27
+ sm: 'px-2.5 py-1 text-xs leading-none',
28
+ md: 'px-3 py-1.5 text-sm',
29
+ lg: 'px-4 py-2 text-base',
30
+ }
31
+
32
+ const typeClasses: Record<BadgeView, Partial<Record<BadgeType, string>>> = {
33
+ default: {
34
+ primary: 'bg-blue-700 text-white dark:bg-blue-500 dark:text-gray-900',
35
+ success: 'bg-green-500 text-white dark:bg-green-400 dark:text-gray-900',
36
+ danger: 'bg-red-500 text-white dark:text-gray-100',
37
+ warning: 'bg-yellow-400 text-white dark:text-gray-900',
38
+ gray: 'bg-deepblue-900 text-white dark:bg-gray-200/10 dark:text-gray-200',
39
+ orange: 'bg-orange-600 text-white dark:text-gray-100',
40
+ },
41
+ inverted: {
42
+ primary: 'bg-blue-700/10 text-blue-700 dark:bg-blue-500/10 dark:text-blue-500',
43
+ success: 'bg-green-500/15 text-green-600 dark:bg-green-400/15 dark:text-green-400',
44
+ danger: 'bg-red-500/10 text-red-500 dark:bg-red-400/10 dark:text-red-400',
45
+ warning: 'bg-yellow-400/15 text-yellow-500 dark:bg-yellow-400/15 dark:text-yellow-400',
46
+ gray: 'bg-deepblue-900/10 text-gray-600 dark:bg-gray-200/10 dark:text-gray-300',
47
+ orange: 'bg-orange-600/10 text-orange-600 dark:text-orange-500',
48
+ },
49
+ transparent: {
50
+ primary: 'bg-transparent text-blue-700 dark:text-blue-500',
51
+ success: 'bg-transparent text-green-600 dark:text-green-400',
52
+ danger: 'bg-transparent text-red-500 dark:text-red-400',
53
+ warning: 'bg-transparent text-yellow-500 dark:text-yellow-400',
54
+ gray: 'bg-transparent text-gray-600 dark:text-gray-300',
55
+ orange: 'bg-transparent text-orange-600 dark:text-orange-500',
56
+ },
57
+ }
58
+
59
+ const attrs = useAttrs()
60
+
61
+ // twMerge resolves Tailwind conflicts: any class passed via `class` wins over
62
+ // the defaults below, so padding / rounded / bg / text can all be overridden.
63
+ const classes = computed(() =>
64
+ twMerge(
65
+ base,
66
+ sizeClasses[props.size],
67
+ typeClasses[props.view][props.type],
68
+ attrs.class as string,
69
+ ),
70
+ )
71
+ </script>
72
+
73
+ <template>
74
+ <div :class="classes" v-bind="{ ...$attrs, class: undefined }">
75
+ <slot name="point" />
76
+ <slot />
77
+ </div>
78
+ </template>
@@ -1,16 +1,10 @@
1
1
  <script setup lang="ts">
2
- import { PAGES } from '#adata-ui/shared/constans/pages'
3
2
  import { usePkServicesLinks } from '#adata-ui/composables/useHeaderNavigationLinks'
4
- import { useUrls } from '#adata-ui/composables/useUrls'
3
+ import { useActiveNavigation } from '#adata-ui/composables/useActiveNavigation'
5
4
  import { NuxtLinkLocale } from '#components'
6
5
 
7
6
  const services = usePkServicesLinks()
8
- const route = useRoute()
9
- const localePath = useLocalePath()
10
- const { landing } = useUrls()
11
- const { locale } = useI18n()
12
-
13
- const pageUrl = useRequestURL()
7
+ const { isActiveService } = useActiveNavigation()
14
8
 
15
9
  const blockStyles = [
16
10
  'first-border-gradient',
@@ -23,22 +17,6 @@ const blockStyles = [
23
17
  'eighth-border-gradient',
24
18
  'ninth-border-gradient',
25
19
  ]
26
- const linkByIndex = [
27
- PAGES.pk.main,
28
- PAGES.pk.employees,
29
- PAGES.pk.connections,
30
- PAGES.pk.offshore,
31
- PAGES.pk.foreign,
32
- PAGES.pk.unload,
33
- PAGES.pk.compare,
34
- PAGES.pk.sanctions,
35
- buildLocalizedUrl(locale, landing, '/all-services'),
36
- ]
37
-
38
- const normalize = (path: string) => {
39
- const cleaned = path.replace(/\/+$/, '')
40
- return cleaned === '' ? '/' : cleaned
41
- }
42
20
  </script>
43
21
 
44
22
  <template>
@@ -46,15 +24,15 @@ const normalize = (path: string) => {
46
24
  <component
47
25
  v-for="(service, index) in services"
48
26
  :key="index"
49
- :is="normalize(localePath(service.short)) === normalize(route.path) && pageUrl.hostname.startsWith('pk') ? 'div' : NuxtLinkLocale"
50
- :to="normalize(localePath(service.short)) === normalize(route.path) ? '' : service.to"
27
+ :is="isActiveService(service.to) ? 'div' : NuxtLinkLocale"
28
+ :to="isActiveService(service.to) ? '' : service.to"
51
29
  :class="['flex flex-col items-center gap-2 p-2', blockStyles[index]]"
52
30
  >
53
31
  <div
54
32
  class="size-10 p-2 rounded-lg"
55
33
  :class="[
56
34
  'bg-deepblue-900/5 dark:bg-gray-200/5',
57
- {'!bg-blue-700 text-white dark:!bg-blue-500 ': route.path.replace(/\/+$/, '') === localePath(linkByIndex[index]).replace(/\/+$/, '')}
35
+ {'!bg-blue-700 text-white dark:!bg-blue-500 ': isActiveService(service.to)}
58
36
  ]"
59
37
  >
60
38
  <component
@@ -0,0 +1,229 @@
1
+ <script setup lang="ts">
2
+ type Size = 'sm' | 'md' | 'lg'
3
+ type Side = 'left' | 'right'
4
+ type View = 'checkbox' | 'chip'
5
+
6
+ const props = withDefaults(defineProps<{
7
+ value?: string | number | boolean | Record<string, unknown> | null
8
+ view?: View
9
+ size?: Size
10
+ side?: Side
11
+ intermediate?: boolean
12
+ disabled?: boolean
13
+ name?: string
14
+ label?: string
15
+ }>(), {
16
+ value: null,
17
+ view: 'checkbox',
18
+ size: 'md',
19
+ side: 'right',
20
+ intermediate: false,
21
+ disabled: false,
22
+ })
23
+
24
+ const modelValue = defineModel<boolean | unknown[]>({ required: true })
25
+
26
+ const slots = useSlots()
27
+
28
+ const isChecked = computed(() => {
29
+ const v = modelValue.value
30
+ if (Array.isArray(v)) return v.includes(props.value as never)
31
+ return v === true
32
+ })
33
+
34
+ const ariaChecked = computed<'true' | 'false' | 'mixed'>(() => {
35
+ if (props.intermediate) return 'mixed'
36
+ return isChecked.value ? 'true' : 'false'
37
+ })
38
+
39
+ const hasLabel = computed(() => Boolean(props.label) || Boolean(slots.default?.().length))
40
+
41
+ function toggle() {
42
+ if (props.disabled) return
43
+
44
+ const current = modelValue.value
45
+ if (Array.isArray(current)) {
46
+ const next = [...current]
47
+ const idx = next.indexOf(props.value as never)
48
+ if (idx === -1) next.push(props.value as never)
49
+ else next.splice(idx, 1)
50
+ modelValue.value = next
51
+ }
52
+ else {
53
+ modelValue.value = !current
54
+ }
55
+ }
56
+
57
+ const gapClass = computed(() => {
58
+ switch (props.size) {
59
+ case 'sm': return 'gap-1.5'
60
+ case 'lg': return 'gap-2.5'
61
+ default: return 'gap-2'
62
+ }
63
+ })
64
+
65
+ const textClass = computed(() => {
66
+ switch (props.size) {
67
+ case 'sm': return 'text-xs'
68
+ case 'lg': return 'text-base'
69
+ default: return 'text-sm'
70
+ }
71
+ })
72
+
73
+ const squareSizeClass = computed(() => {
74
+ switch (props.size) {
75
+ case 'sm': return 'size-4'
76
+ case 'lg': return 'size-6'
77
+ default: return 'size-[18px]'
78
+ }
79
+ })
80
+
81
+ const isActive = computed(() => isChecked.value || props.intermediate)
82
+
83
+ const squareClass = computed(() => {
84
+ const base = [
85
+ 'checkbox-square inline-flex shrink-0 items-center justify-center rounded-md border transition-colors duration-150',
86
+ squareSizeClass.value,
87
+ ]
88
+
89
+ if (isActive.value) {
90
+ base.push('border-transparent bg-blue-700 text-white dark:bg-blue-500')
91
+ }
92
+ else {
93
+ base.push('border-gray-300 bg-white text-transparent dark:border-gray-600 dark:bg-white/[0.04]')
94
+ if (!props.disabled) {
95
+ base.push('group-hover/cb:border-blue-500 dark:group-hover/cb:border-blue-400')
96
+ }
97
+ }
98
+
99
+ return base.join(' ')
100
+ })
101
+
102
+ const chipClass = computed(() => {
103
+ const base = [
104
+ 'inline-flex items-center rounded-full border px-3 py-1 text-xs transition-colors duration-150',
105
+ ]
106
+
107
+ if (isActive.value) {
108
+ base.push('border-transparent bg-blue-700 text-white dark:bg-blue-500 dark:text-gray-900')
109
+ }
110
+ else {
111
+ base.push('border-gray-300 bg-transparent text-gray-700 dark:border-gray-600 dark:text-gray-300')
112
+ if (!props.disabled) {
113
+ base.push('group-hover/cb:border-gray-400 dark:group-hover/cb:border-gray-500')
114
+ }
115
+ }
116
+
117
+ return base.join(' ')
118
+ })
119
+
120
+ const labelClass = computed(() => `${textClass.value} leading-none text-deepblue-900 dark:text-gray-200`)
121
+
122
+ const rootClass = computed(() => {
123
+ const base = [
124
+ 'checkbox-v2 group/cb inline-flex items-center select-none rounded transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900',
125
+ ]
126
+
127
+ if (props.view === 'checkbox') {
128
+ base.push(gapClass.value)
129
+ }
130
+
131
+ if (props.disabled) {
132
+ base.push('cursor-not-allowed opacity-50')
133
+ }
134
+ else {
135
+ base.push('cursor-pointer')
136
+ }
137
+
138
+ return base.join(' ')
139
+ })
140
+ </script>
141
+
142
+ <template>
143
+ <button
144
+ type="button"
145
+ role="checkbox"
146
+ :aria-checked="ariaChecked"
147
+ :aria-disabled="disabled || undefined"
148
+ :disabled="disabled"
149
+ :name="name"
150
+ :class="rootClass"
151
+ @click="toggle"
152
+ @keydown.space.prevent="toggle"
153
+ >
154
+ <template v-if="view === 'checkbox'">
155
+ <span v-if="side === 'left' && hasLabel" :class="labelClass">
156
+ <slot>{{ label }}</slot>
157
+ </span>
158
+
159
+ <span :class="squareClass">
160
+ <svg
161
+ v-if="intermediate"
162
+ class="checkbox-intermediate size-3/4"
163
+ viewBox="0 0 16 16"
164
+ fill="none"
165
+ stroke="currentColor"
166
+ aria-hidden="true"
167
+ >
168
+ <line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round" />
169
+ </svg>
170
+ <svg
171
+ v-else-if="isChecked"
172
+ class="checkbox-check size-3/4"
173
+ viewBox="0 0 16 16"
174
+ fill="none"
175
+ stroke="currentColor"
176
+ aria-hidden="true"
177
+ >
178
+ <path
179
+ d="M3 8.5 L6.5 12 L13 4.5"
180
+ stroke-width="2"
181
+ stroke-linecap="round"
182
+ stroke-linejoin="round"
183
+ />
184
+ </svg>
185
+ </span>
186
+
187
+ <span v-if="side === 'right' && hasLabel" :class="labelClass">
188
+ <slot>{{ label }}</slot>
189
+ </span>
190
+ </template>
191
+
192
+ <span v-else :class="chipClass">
193
+ <slot>{{ label }}</slot>
194
+ </span>
195
+ </button>
196
+ </template>
197
+
198
+ <style scoped lang="scss">
199
+ .checkbox-check path {
200
+ stroke-dasharray: 22;
201
+ stroke-dashoffset: 22;
202
+ animation: check-draw 220ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
203
+ }
204
+
205
+ .checkbox-intermediate line {
206
+ stroke-dasharray: 14;
207
+ stroke-dashoffset: 14;
208
+ animation: check-draw 160ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
209
+ }
210
+
211
+ @keyframes check-draw {
212
+ to {
213
+ stroke-dashoffset: 0;
214
+ }
215
+ }
216
+
217
+ @media (prefers-reduced-motion: reduce) {
218
+ .checkbox-check path,
219
+ .checkbox-intermediate line {
220
+ animation: none;
221
+ stroke-dashoffset: 0;
222
+ }
223
+
224
+ .checkbox-v2,
225
+ .checkbox-square {
226
+ transition: none;
227
+ }
228
+ }
229
+ </style>
@@ -152,26 +152,26 @@ onMounted(() => {
152
152
  </AButton>
153
153
  </section>
154
154
 
155
- <a-modal
155
+ <a-modal-v2
156
156
  v-model="isModalOpen"
157
157
  width="424px"
158
158
  @close="isModalOpen = false"
159
159
  >
160
- <div class="flex flex-col items-center gap-5">
161
- <h4 class="heading-04">
160
+ <div class="flex flex-col items-center gap-4 px-6 py-4">
161
+ <a-ill-mail />
162
+ <h4 class="text-[18px] font-semibold">
162
163
  {{ t('forms.feedback.modalTitle') }}
163
164
  </h4>
164
- <a-ill-mail />
165
165
  <p class="body-400 max-[352xp]">
166
166
  {{ t('forms.feedback.modalSubtitle') }}
167
167
  </p>
168
- <AButton
169
- block
168
+ <a-button-v2
170
169
  view="outline"
170
+ block
171
171
  @click="isModalOpen = false"
172
172
  >
173
173
  {{ t('forms.feedback.close') }}
174
- </AButton>
174
+ </a-button-v2>
175
175
  </div>
176
- </a-modal>
176
+ </a-modal-v2>
177
177
  </template>