adata-ui 2.1.40-beta.18 → 2.1.40-beta.19

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 (211) hide show
  1. package/.playground/app.vue +102 -0
  2. package/assets/styles/index.scss +67 -5
  3. package/components/elements/a-select-row/ASelectRowV2.vue +214 -0
  4. package/components/elements/a-select-row/index.vue +3 -5
  5. package/components/elements/accordion/AAccordion.vue +5 -3
  6. package/components/elements/accordion/AAccordionGroup/AAccordionGroup.vue +3 -3
  7. package/components/elements/alert/AAlert.vue +34 -47
  8. package/components/elements/bg-block/ABgBlock.vue +1 -1
  9. package/components/elements/button/AButton.vue +3 -3
  10. package/components/elements/button/AButtonV2.vue +133 -0
  11. package/components/elements/button-login/index.vue +6 -10
  12. package/components/elements/chip-wrapper/AChipWrapper.vue +1 -1
  13. package/components/elements/chips/AChips.vue +2 -2
  14. package/components/elements/companies/AOurClients.vue +3 -1
  15. package/components/elements/curve-block-v2/ACurveBlockV2.vue +85 -0
  16. package/components/elements/digit-badge/ADigitBadge.vue +24 -22
  17. package/components/elements/feature-description/AFeatureDescription.vue +1 -1
  18. package/components/elements/leave-note/ALeaveNote.vue +39 -18
  19. package/components/elements/pagination/APagination.vue +7 -7
  20. package/components/elements/segmented/ASegmentedV2.vue +151 -0
  21. package/components/elements/select/ASelect.vue +4 -4
  22. package/components/elements/select/ASelectMobile.vue +2 -2
  23. package/components/elements/select/ASelectV2.vue +588 -0
  24. package/components/elements/select/ui/select-button.vue +1 -1
  25. package/components/elements/show-more/AShowMoreV2.vue +26 -0
  26. package/components/elements/slider/ASlider.vue +174 -0
  27. package/components/elements/slider/ASliderItem.vue +31 -0
  28. package/components/elements/slider/types.ts +21 -0
  29. package/components/elements/star-rating/AStarRating.vue +12 -4
  30. package/components/elements/status-badge/AStatusBadge.vue +91 -44
  31. package/components/elements/step-slider/AStepSliderColCard.vue +232 -0
  32. package/components/elements/step-slider/AStepSliderColNumber.vue +178 -0
  33. package/components/elements/table/ATable.vue +1 -1
  34. package/components/elements/table/table.config.ts +2 -2
  35. package/components/elements/tree-select/ATreeSelect.vue +97 -113
  36. package/components/elements/tree-select/TreeService.ts +142 -207
  37. package/components/elements/tree-select/components/ATreeSelectNode.vue +104 -0
  38. package/components/elements/tree-select/types.ts +40 -11
  39. package/components/elements/tree-select/utils.ts +30 -0
  40. package/components/elements/tree-select-modal/ATreeSelectModal.vue +217 -0
  41. package/components/features/color-mode/AColorMode.client.vue +74 -32
  42. package/components/features/dropdown/ADropdownV2.vue +140 -0
  43. package/components/features/lang-switcher/lang-switcher.vue +125 -40
  44. package/components/features/payment/banner/BasicPlusLimitBanner.vue +3 -3
  45. package/components/features/payment/banner/PaymentBanner.vue +3 -3
  46. package/components/features/payment/banner/UpSellBanner.vue +3 -3
  47. package/components/features/payment/process/PaymentKaspiQrSidePanel.vue +45 -27
  48. package/components/features/payment/process/PaymentKaspiRedirectSidePanel.vue +34 -23
  49. package/components/features/payment/process/PaymentMethodSidePanel.vue +66 -49
  50. package/components/features/payment/process/PaymentProcess.vue +6 -6
  51. package/components/features/payment/process/PaymentTopUpSidePanel.vue +49 -63
  52. package/components/features/pk-mobile-services/APkMobileServices.vue +6 -28
  53. package/components/features//321/201hange-version/AChangeVersion.vue +2 -2
  54. package/components/forms/checkbox/ACheckbox.vue +1 -1
  55. package/components/forms/checkbox/ACheckboxV2.vue +229 -0
  56. package/components/forms/feedback-form/FeedbackForm.vue +8 -8
  57. package/components/forms/feedback-form/FeedbackFormV2.vue +182 -0
  58. package/components/forms/input/AInputV2.vue +542 -0
  59. package/components/forms/input/date/AInputDate.vue +2 -2
  60. package/components/forms/input/password/AInputPassword.vue +8 -2
  61. package/components/forms/input/standard/AInputStandard.vue +3 -3
  62. package/components/forms/input/textarea/ATextarea.vue +2 -2
  63. package/components/forms/input/textarea/ATextareaV2.vue +248 -0
  64. package/components/forms/toggle/AToggle.vue +2 -3
  65. package/components/forms/toggle/AToggleV2.vue +71 -0
  66. package/components/modals/AnotherDeviceModal.vue +22 -18
  67. package/components/modals/ApplicationAcceptedModal.vue +12 -15
  68. package/components/modals/ConnectingTariffModal.vue +13 -20
  69. package/components/modals/ContactsMobileModel.vue +1 -1
  70. package/components/modals/ContentNavigationModal.vue +77 -333
  71. package/components/modals/Insufficient-funds-modal.vue +18 -33
  72. package/components/modals/LimitReachedModal.vue +17 -14
  73. package/components/modals/NoAccessModal.vue +9 -11
  74. package/components/modals/PaymentMethodModal.vue +1 -1
  75. package/components/modals/ReportBugConfirmModal.vue +12 -10
  76. package/components/modals/ReportBugModal.vue +46 -38
  77. package/components/modals/Resend.vue +9 -10
  78. package/components/modals/SubmitApplicationModal.vue +27 -24
  79. package/components/modals/id/IdBanner.vue +3 -3
  80. package/components/modals/id/IdConfirmAccountOtpModal.vue +4 -9
  81. package/components/modals/id/IdLoginModal.vue +3 -8
  82. package/components/modals/id/IdModals.vue +23 -10
  83. package/components/modals/id/IdRecoveryModal.vue +1 -1
  84. package/components/modals/id/IdTwoFactorModal.vue +3 -8
  85. package/components/navigation/bottom-navigation/ABottomNavigation.vue +1 -1
  86. package/components/navigation/breadcrumbs/ABreadcrumbs.vue +106 -45
  87. package/components/navigation/breadcrumbs/types.ts +3 -0
  88. package/components/navigation/footer/AFooter.vue +39 -40
  89. package/components/navigation/footer/ui/a-footer-accordion.vue +9 -9
  90. package/components/navigation/header/AHeader.vue +68 -51
  91. package/components/navigation/header/AlmatyContacts.vue +78 -78
  92. package/components/navigation/header/CardGallery.vue +9 -7
  93. package/components/navigation/header/ContactMenu.vue +26 -92
  94. package/components/navigation/header/HeaderLink.vue +181 -213
  95. package/components/navigation/header/HeaderUsage.vue +139 -0
  96. package/components/navigation/header/ListItem.vue +2 -2
  97. package/components/navigation/header/NavCard.vue +1 -1
  98. package/components/navigation/header/NavList.vue +33 -92
  99. package/components/navigation/header/NotificationsMenu.vue +2 -3
  100. package/components/navigation/header/ProductMenu.vue +81 -127
  101. package/components/navigation/header/ProfileMenu.vue +122 -151
  102. package/components/navigation/header/SystemNotification.vue +108 -0
  103. package/components/navigation/mobile-navigation/AMobileNavigation.vue +23 -15
  104. package/components/navigation/pill-tabs/APillTabs.vue +2 -2
  105. package/components/navigation/pill-tabs/APillTabsV2.vue +226 -0
  106. package/components/overlays/drawer/ADrawerV2.vue +335 -0
  107. package/components/overlays/modal/AModal.vue +4 -4
  108. package/components/overlays/modal/AModalV2.vue +397 -0
  109. package/components/overlays/side-panel/ASidePanel.vue +10 -7
  110. package/components/overlays/sideover/ASlideover.vue +6 -6
  111. package/components/overlays/tooltip/ATooltip.vue +1 -1
  112. package/components/overlays/tooltip/ATooltipV2.vue +223 -0
  113. package/components/overlays/tooltip/types.ts +26 -0
  114. package/components/overlays/tooltip/useTooltipTrigger.ts +101 -0
  115. package/components/transitions/ATransitionHeight.vue +1 -1
  116. package/composables/useAccessTokenCookie.ts +25 -0
  117. package/composables/useActiveNavigation.ts +84 -0
  118. package/composables/useChipOverflow.ts +92 -0
  119. package/composables/useHeaderNavigationLinks.ts +140 -98
  120. package/icons/archive.vue +16 -0
  121. package/icons/arrow/arrow-left-right.vue +8 -0
  122. package/icons/arrow/arrow-right.vue +14 -0
  123. package/icons/arrow/arrows-in.vue +11 -0
  124. package/icons/arrow/arrows-out.vue +11 -0
  125. package/icons/arrow/arrows-resize-in.vue +38 -0
  126. package/icons/arrow/arrows-resize-out.vue +17 -0
  127. package/icons/bill.vue +3 -0
  128. package/icons/bot.vue +52 -0
  129. package/icons/briefcase.vue +14 -0
  130. package/icons/building.vue +9 -0
  131. package/icons/car-side.vue +16 -0
  132. package/icons/cart.vue +15 -0
  133. package/icons/chart-no-axes-column.vue +3 -0
  134. package/icons/clock-time.vue +24 -0
  135. package/icons/cloud/cloud-upload.vue +3 -0
  136. package/icons/code.vue +9 -0
  137. package/icons/compare-outlined.vue +8 -0
  138. package/icons/dots-horizontal.vue +31 -0
  139. package/icons/download-line.vue +13 -0
  140. package/icons/download-rounded.vue +15 -0
  141. package/icons/egov.vue +41 -0
  142. package/icons/elicense.vue +38 -0
  143. package/icons/favourite-bookmark-outline.vue +17 -0
  144. package/icons/file/file-check-corner.vue +3 -0
  145. package/icons/file/file-spreadsheet.vue +3 -0
  146. package/icons/file-pen.vue +31 -0
  147. package/icons/file-stack.vue +31 -0
  148. package/icons/file-types/excel.vue +131 -0
  149. package/icons/file-types/html.vue +13 -0
  150. package/icons/file-types/jpeg.vue +16 -0
  151. package/icons/file-types/pdf.vue +11 -0
  152. package/icons/file-types/png.vue +11 -0
  153. package/icons/file-types/rar.vue +11 -0
  154. package/icons/file-types/word.vue +50 -0
  155. package/icons/file-types/zip.vue +11 -0
  156. package/icons/gauge.vue +17 -0
  157. package/icons/git-compare.vue +38 -0
  158. package/icons/git-fork.vue +3 -0
  159. package/icons/graduation-cap.vue +31 -0
  160. package/icons/graph-loading.vue +34 -0
  161. package/icons/headset.vue +6 -0
  162. package/icons/help-question-circle.vue +26 -0
  163. package/icons/in-row-type.vue +46 -0
  164. package/icons/in-table-type.vue +29 -0
  165. package/icons/landmark.vue +3 -0
  166. package/icons/layers.vue +3 -0
  167. package/icons/letter/letter-a.vue +6 -0
  168. package/icons/letter/letter-b.vue +6 -0
  169. package/icons/letter/letter-c.vue +6 -0
  170. package/icons/letter/letter-d.vue +6 -0
  171. package/icons/letter/letter-e.vue +6 -0
  172. package/icons/link-url.vue +3 -0
  173. package/icons/list-tree.vue +3 -0
  174. package/icons/mail-question-mark.vue +8 -0
  175. package/icons/message/message-square.vue +3 -0
  176. package/icons/message-dotted.vue +30 -0
  177. package/icons/network.vue +3 -0
  178. package/icons/newspaper.vue +3 -0
  179. package/icons/notification-error.vue +17 -0
  180. package/icons/person.vue +22 -0
  181. package/icons/phone-call.vue +6 -0
  182. package/icons/phone-reversed.vue +3 -0
  183. package/icons/route.vue +7 -0
  184. package/icons/scan-search.vue +3 -0
  185. package/icons/settings.vue +26 -0
  186. package/icons/shield-alert.vue +31 -0
  187. package/icons/shield-verified.vue +14 -0
  188. package/icons/socials/facebook-color.vue +16 -0
  189. package/icons/socials/globe-color.vue +16 -0
  190. package/icons/socials/instagram-color.vue +46 -0
  191. package/icons/socials/linkedin-color.vue +14 -0
  192. package/icons/socials/telegram-color.vue +16 -0
  193. package/icons/socials/tiktok-color.vue +14 -0
  194. package/icons/socials/vk-color.vue +16 -0
  195. package/icons/socials/youtube-color.vue +16 -0
  196. package/icons/sparkles.vue +3 -0
  197. package/icons/sun.vue +13 -3
  198. package/icons/users-round.vue +3 -0
  199. package/icons/view-eye-open.vue +13 -0
  200. package/icons/workflow.vue +3 -0
  201. package/icons/zap.vue +3 -0
  202. package/lang/en.ts +49 -5
  203. package/lang/kk.ts +50 -6
  204. package/lang/ru.ts +51 -7
  205. package/package.json +1 -1
  206. package/plugins/toast.client.ts +38 -55
  207. package/shared/constans/pages.ts +8 -2
  208. package/tailwind.config.ts +147 -116
  209. package/utils/twMerge.ts +34 -0
  210. package/components/elements/tree-select/components/tree-select-nodes.vue +0 -91
  211. package/components/navigation/header/TopHeader.vue +0 -196
@@ -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
- class="size-10 p-2 rounded-lg"
32
+ class="size-10 p-2 rounded-md"
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
@@ -10,9 +10,9 @@ const { t } = useI18n()
10
10
  <nuxt-link
11
11
  :to="url"
12
12
  target="_blank"
13
- class="flex cursor-pointer items-center justify-center gap-1 rounded-md bg-blue-700/10 px-3 py-2 text-blue-700"
13
+ class="flex cursor-pointer items-center justify-center gap-1 rounded-sm bg-blue-700/10 px-3 py-2 text-blue-700 transition-colors duration-150 hover:bg-blue-700/15 dark:bg-blue-400/10 dark:text-blue-300 dark:hover:bg-blue-400/20"
14
14
  >
15
- <span class="body-400">{{ t('header.oldVersion') }}</span>
15
+ <span class="text-body-md">{{ t('header.oldVersion') }}</span>
16
16
  <a-icon-arrow-bottom-left-on-square class="rotate-180" />
17
17
  </nuxt-link>
18
18
  </template>
@@ -58,7 +58,7 @@
58
58
  </template>
59
59
 
60
60
  <script setup lang="ts">
61
- import { twMerge } from 'tailwind-merge'
61
+ import { twMerge } from '#adata-ui/utils/twMerge'
62
62
 
63
63
 
64
64
  defineOptions({ name: 'ACheckbox' })
@@ -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-body-sm'
68
+ case 'lg': return 'text-body-lg'
69
+ default: return 'text-body-md'
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-sm 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-body-sm 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>
@@ -0,0 +1,182 @@
1
+ <script lang="ts" setup>
2
+ import * as z from 'zod'
3
+ import { useUIValidation } from '#adata-ui/composables/useUIValidation'
4
+ import MessageSquare from '#adata-ui/icons/message/message-square.vue'
5
+ import AInputV2 from '#adata-ui/components/forms/input/AInputV2.vue'
6
+ import ATextareaV2 from '#adata-ui/components/forms/input/textarea/ATextareaV2.vue'
7
+ import AButtonV2 from '#adata-ui/components/elements/button/AButtonV2.vue'
8
+
9
+ const props = withDefaults(defineProps<{
10
+ userInfo: any
11
+ title?: string
12
+ subtitle?: string
13
+ }>(), {
14
+ title: undefined,
15
+ subtitle: undefined,
16
+ })
17
+
18
+ const emit = defineEmits(['submit'])
19
+
20
+ const { t } = useI18n()
21
+
22
+ const isLoading = defineModel< null | any>('isLoading', { default: false })
23
+ const isModalOpen = defineModel< null | any>('isModalOpen', { default: false })
24
+
25
+ const fullName = ref<string>('')
26
+ const phone = ref<string>('')
27
+ const mail = ref<string>('')
28
+ const comment = ref<string>('')
29
+
30
+ const submitted = ref(false)
31
+
32
+ const scheme = z.object({
33
+ fullName: z.string().nonempty(t('forms.feedback.fieldRequired')),
34
+ phone: z.string().nonempty(t('forms.feedback.fieldRequired')).min(17, t('forms.feedback.phoneMinLength', { count: 10 })),
35
+ mail: z.string().nonempty(t('forms.feedback.fieldRequired')).email(t('forms.feedback.emailValid')),
36
+ comment: z.string().nonempty(t('forms.feedback.fieldRequired')).min(10, t('forms.feedback.commentMinLength', { count: 10 })).max(250, t('forms.feedback.commentMaxLength', { count: 250 })),
37
+ })
38
+
39
+ const { validation, getError } = useUIValidation(
40
+ scheme,
41
+ () => ({
42
+ fullName: fullName.value,
43
+ phone: phone.value,
44
+ mail: mail.value,
45
+ comment: comment.value,
46
+ }),
47
+ submitted,
48
+ )
49
+
50
+ const send = () => {
51
+ submitted.value = true
52
+ if (validation.value) return;
53
+
54
+ emit('submit', { sender_name: fullName.value, phone_number: phone.value, email: mail.value, message: comment.value })
55
+ submitted.value = false
56
+ fullName.value = ''
57
+ phone.value = ''
58
+ mail.value = props.userInfo?.email || ''
59
+ comment.value = ''
60
+ }
61
+
62
+ defineExpose({
63
+ reset: () => (submitted.value = false),
64
+ })
65
+
66
+ onMounted(() => {
67
+ mail.value = props.userInfo?.email || ''
68
+ })
69
+ </script>
70
+
71
+ <template>
72
+ <section class="feedback-v2">
73
+ <div class="grid grid-cols-1 items-center gap-8 rounded-[28px] border border-blue-100 bg-gradient-to-br from-blue-50 to-blue-100 p-4 md:gap-10 md:p-12 lg:grid-cols-2">
74
+ <div>
75
+ <div class="mb-4 inline-flex items-center gap-2 rounded-full border border-blue-100 bg-white px-3 py-1.5 text-body-md text-blue-600">
76
+ <message-square class="size-3.5" />
77
+ {{ t('forms.feedback.value') }}
78
+ </div>
79
+
80
+ <h2 class="text-h2 md:text-display-sm">
81
+ {{ title ?? t('forms.feedback.title') }}
82
+ </h2>
83
+ <p class="mt-3 max-w-[448px] text-body-sm md:text-body-lg text-gray-600">
84
+ {{ subtitle ?? t('forms.feedback.subtitle') }}
85
+ </p>
86
+
87
+ <div class="mt-6 flex flex-col gap-3">
88
+ <slot name="contacts" />
89
+ </div>
90
+ </div>
91
+
92
+ <div class="rounded-[24px] border border-gray-200 bg-white p-4 md:p-7 shadow-xl shadow-blue-600/10">
93
+ <form
94
+ class="flex flex-col gap-3"
95
+ @submit.prevent="send"
96
+ >
97
+ <a-input-v2
98
+ v-model="fullName"
99
+ variant="gray"
100
+ size="md"
101
+ required
102
+ :label="t('forms.demo.n')"
103
+ :error="getError('fullName')"
104
+ :disabled="isLoading"
105
+ />
106
+ <div class="grid grid-cols-1 gap-3 sm:grid-cols-2">
107
+ <a-input-v2
108
+ v-model="phone"
109
+ type="tel"
110
+ variant="gray"
111
+ size="md"
112
+ required
113
+ mask="8 (###) ###-##-##"
114
+ :label="t('forms.feedback.phone')"
115
+ :error="getError('phone')"
116
+ :disabled="isLoading"
117
+ />
118
+ <a-input-v2
119
+ v-model="mail"
120
+ type="email"
121
+ variant="gray"
122
+ size="md"
123
+ required
124
+ :label="t('forms.feedback.email')"
125
+ :error="getError('mail')"
126
+ :disabled="isLoading"
127
+ />
128
+ </div>
129
+ <a-textarea-v2
130
+ v-model="comment"
131
+ variant="gray"
132
+ size="md"
133
+ :rows="4"
134
+ resize="none"
135
+ :label="t('forms.feedback.comment')"
136
+ :error="getError('comment')"
137
+ :disabled="isLoading"
138
+ required
139
+ />
140
+ <a-button-v2
141
+ type="submit"
142
+ size="lg"
143
+ block
144
+ class="mt-1"
145
+ :loading="isLoading"
146
+ >
147
+ {{ t('forms.feedback.send') }}
148
+ </a-button-v2>
149
+ <p class="mt-1 text-center text-body-sm text-gray-400">
150
+ {{ t('forms.feedback.consent') }}
151
+ <span class="text-blue-600">
152
+ {{ t('forms.feedback.consentAccent') }}
153
+ </span>
154
+ </p>
155
+ </form>
156
+ </div>
157
+ </div>
158
+ </section>
159
+
160
+ <a-modal-v2
161
+ v-model="isModalOpen"
162
+ width="424px"
163
+ @close="isModalOpen = false"
164
+ >
165
+ <div class="flex flex-col items-center gap-4 px-6 py-4">
166
+ <a-ill-mail />
167
+ <h4 class="text-[18px] font-semibold">
168
+ {{ t('forms.feedback.modalTitle') }}
169
+ </h4>
170
+ <p class="body-400 max-[352xp]">
171
+ {{ t('forms.feedback.modalSubtitle') }}
172
+ </p>
173
+ <a-button-v2
174
+ view="outline"
175
+ block
176
+ @click="isModalOpen = false"
177
+ >
178
+ {{ t('forms.feedback.close') }}
179
+ </a-button-v2>
180
+ </div>
181
+ </a-modal-v2>
182
+ </template>