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
@@ -18,7 +18,7 @@ const env = myLayer.mode
18
18
 
19
19
  const mask = new Mask({ mask: '# (###) ### ## ##' })
20
20
 
21
- const isOpen = defineModel<boolean>()
21
+ const isOpen = defineModel<boolean>({ default: false })
22
22
  const form: any = reactive({
23
23
  name: '',
24
24
  email: '',
@@ -28,13 +28,13 @@ const form: any = reactive({
28
28
  const phone = ref(form.phone_number)
29
29
 
30
30
  const scheme = z.object({
31
- name: z.string().nonempty(t('modals.report_bug.validation.required')),
32
31
  email: z.string().nonempty(t('modals.report_bug.validation.required')).email(t('modals.submit_application_modal.rules.email')),
33
32
  phone_number: z.string().nonempty(t('modals.report_bug.validation.required')).min(17, t('modals.report_bug.validation.phone', { n: 10 })),
34
33
  comment: z.string().nonempty(t('modals.report_bug.validation.required')),
35
34
  })
36
35
 
37
36
  const submitted = ref(false)
37
+ const sending = ref(false)
38
38
 
39
39
  const { validation, getError } = useUIValidation(
40
40
  scheme,
@@ -58,6 +58,7 @@ watch(phone, () => {
58
58
  async function send() {
59
59
  submitted.value = true
60
60
  if (validation.value) return
61
+ sending.value = true
61
62
  try {
62
63
  await $fetch<any>(`https://users.${env}.kz/api/v1/message/error`, {
63
64
  method: 'POST',
@@ -79,86 +80,93 @@ async function send() {
79
80
  form.comment = ''
80
81
  phone.value = ''
81
82
  submitted.value = false
83
+ sending.value = false
82
84
  emit('close')
83
85
  }
84
86
  }
85
87
  </script>
86
88
 
87
89
  <template>
88
- <a-modal v-model="isOpen" data-test-id="report-form-modal">
90
+ <a-modal-v2
91
+ v-model="isOpen"
92
+ width="424px"
93
+ data-test-id="report-form-modal"
94
+ >
89
95
  <template #header>
90
- <p class="heading-02 text-center" data-test-id="report-form-title">
96
+ <h2 class="text-base font-semibold text-gray-900 dark:text-gray-100" data-test-id="report-form-title">
91
97
  {{ t('modals.report_bug.title') }}
92
- </p>
98
+ </h2>
93
99
  </template>
94
- <div class="flex flex-col gap-5">
95
- <div class="flex flex-col items-center justify-center gap-5">
96
- <a-ill-stop-sign class="size-[185px]" />
100
+
101
+ <div class="flex flex-col gap-5 px-6 py-4">
102
+ <div class="flex flex-col items-center justify-center gap-4">
103
+ <a-ill-stop-sign class="size-[140px]" />
97
104
  <slot name="title">
98
105
  <p class="label-400 text-center">
99
106
  {{ name }}
100
107
  </p>
101
108
  </slot>
102
109
  </div>
103
- <div class="flex flex-col gap-2">
104
- <a-input-standard
110
+
111
+ <div class="flex flex-col gap-3">
112
+ <a-input-v2
105
113
  v-model="form.name"
106
- required
107
- :data-test-id="'report-form-name-input'"
108
114
  :label="t('modals.report_bug.labels.name')"
109
115
  :error="getError('name')"
116
+ data-test-id="report-form-name-input"
110
117
  />
111
- <a-input-standard
118
+ <a-input-v2
112
119
  v-model="form.email"
113
120
  required
114
- :data-test-id="'report-form-email-input'"
121
+ type="email"
115
122
  :label="t('modals.report_bug.labels.email')"
116
123
  :error="getError('email')"
124
+ data-test-id="report-form-email-input"
117
125
  />
118
- <a-input-standard
126
+ <a-input-v2
119
127
  v-model="phone"
120
- v-maska
121
128
  required
122
- data-maska="8 (###) ### ## ##"
129
+ type="tel"
123
130
  clearable
124
- :data-test-id="'report-form-phone-input'"
131
+ mask="8 (###) ### ## ##"
125
132
  :label="t('modals.report_bug.labels.phone')"
126
133
  :error="getError('phone_number')"
134
+ data-test-id="report-form-phone-input"
135
+ />
136
+ <a-textarea-v2
137
+ v-model="form.comment"
138
+ required
139
+ :rows="6"
140
+ resize="none"
141
+ :label="t('modals.report_bug.labels.comment')"
142
+ :error="getError('comment')"
143
+ data-test-id="report-form-comment-textarea"
127
144
  />
128
- <div>
129
- <a-textarea
130
- v-model="form.comment"
131
- required
132
- :data-test-id="'report-form-comment-textarea'"
133
- :label="t('modals.report_bug.labels.comment')"
134
- size="md"
135
- :error="getError('comment')"
136
- class="min-h-[120px]"
137
- :resizeable="false"
138
- />
139
- </div>
140
145
  </div>
141
146
  </div>
147
+
142
148
  <template #footer>
143
- <div class="flex w-full gap-2">
144
- <a-button
149
+ <div class="flex gap-2">
150
+ <a-button-v2
145
151
  view="outline"
146
- class="w-full"
152
+ color="blue"
153
+ block
147
154
  data-test-id="report-form-close-button"
148
155
  @click="emit('close')"
149
156
  >
150
157
  {{ t('actions.close') }}
151
- </a-button>
152
- <a-button
153
- class="w-full"
158
+ </a-button-v2>
159
+ <a-button-v2
160
+ block
161
+ :loading="sending"
154
162
  data-test-id="report-form-submit-button"
155
163
  @click="send"
156
164
  >
157
165
  {{ t('actions.send') }}
158
- </a-button>
166
+ </a-button-v2>
159
167
  </div>
160
168
  </template>
161
- </a-modal>
169
+ </a-modal-v2>
162
170
  </template>
163
171
 
164
172
  <style scoped></style>
@@ -1,5 +1,4 @@
1
1
  <script setup lang="ts">
2
-
3
2
  import { useUrls } from '#adata-ui/composables/useUrls'
4
3
 
5
4
  const emit = defineEmits<{
@@ -17,33 +16,33 @@ function runTimer() {
17
16
  const intervalId = setInterval(() => {
18
17
  if (timer.value <= 0) {
19
18
  isResend.value = true
20
- clearInterval(intervalId);
21
- return;
19
+ clearInterval(intervalId)
20
+ return
22
21
  }
23
- timer.value--;
24
- }, 1000);
22
+ timer.value--
23
+ }, 1000)
25
24
  }
26
25
 
27
26
  onMounted(() => resend())
28
27
 
29
- const resend = () => {
28
+ function resend() {
30
29
  isResend.value = false
31
30
  runTimer()
32
31
  emit('resend')
33
32
  }
34
- const goToMain = () => {
33
+ function goToMain() {
35
34
  if (route.query.url) {
36
35
  document.location.replace(route.query.url)
37
- } else {
36
+ }
37
+ else {
38
38
  document.location.replace(landing)
39
39
  }
40
40
  emit('close')
41
-
42
41
  }
43
42
  </script>
44
43
 
45
44
  <template>
46
- <div class="flex flex-col justify-center items-center gap-5">
45
+ <div class="flex flex-col items-center justify-center gap-5">
47
46
  <p class="heading-02">
48
47
  {{ $t('login.modal.title') }}
49
48
  </p>
@@ -57,65 +57,68 @@ onMounted(() => {
57
57
  </script>
58
58
 
59
59
  <template>
60
- <a-modal
60
+ <a-modal-v2
61
61
  v-model="isOpen"
62
- name="submit-application"
63
- :prevent-close="true"
62
+ width="424px"
63
+ persistent
64
64
  >
65
- <div class="flex flex-col gap-5">
66
- <p class="text-center heading-02">
65
+ <div class="flex flex-col gap-5 px-6 py-4">
66
+ <p class="heading-02 text-center">
67
67
  {{ t('modals.submit_application_modal.title') }}
68
68
  </p>
69
69
  <a-ill-mail class="w-full" />
70
- <div class="flex flex-col gap-2">
71
- <a-input-standard
70
+ <div class="flex flex-col gap-3">
71
+ <a-input-v2
72
72
  v-model="form.name"
73
+ required
73
74
  :label="t('modals.submit_application_modal.labels.name')"
74
75
  :error="getError('name')"
75
- required
76
76
  />
77
- <a-input-standard
77
+ <a-input-v2
78
78
  v-model="form.email"
79
+ required
80
+ type="email"
79
81
  :label="t('modals.submit_application_modal.labels.email')"
80
82
  :error="getError('email')"
81
- required
82
83
  />
83
- <a-input-standard
84
+ <a-input-v2
84
85
  v-model="form.phone"
85
- v-maska
86
+ required
87
+ type="tel"
88
+ clearable
89
+ mask="8 (###) ###-##-##"
86
90
  :label="t('modals.submit_application_modal.labels.phone')"
87
- data-maska="8 (###) ###-##-##"
88
91
  :error="getError('phone')"
89
- clearable
90
- required
91
92
  />
92
- <a-textarea
93
+ <a-textarea-v2
93
94
  v-model="form.comment"
95
+ required
96
+ :rows="4"
97
+ resize="none"
94
98
  :label="t('modals.submit_application_modal.labels.comment')"
95
99
  :error="getError('comment')"
96
- resizeable="none"
97
- required
98
100
  />
99
101
  </div>
100
102
  </div>
101
103
  <template #footer>
102
- <div class="flex gap-2 ">
103
- <a-button
104
+ <div class="flex gap-2">
105
+ <a-button-v2
104
106
  view="outline"
107
+ color="blue"
105
108
  block
106
109
  @click="cancel"
107
110
  >
108
111
  {{ t('reuse.close') }}
109
- </a-button>
110
- <a-button
112
+ </a-button-v2>
113
+ <a-button-v2
111
114
  block
112
115
  @click="send"
113
116
  >
114
117
  {{ t('reuse.send') }}
115
- </a-button>
118
+ </a-button-v2>
116
119
  </div>
117
120
  </template>
118
- </a-modal>
121
+ </a-modal-v2>
119
122
  </template>
120
123
 
121
124
  <style scoped>
@@ -9,15 +9,15 @@ function onRegister() {
9
9
  </script>
10
10
 
11
11
  <template>
12
- <div class="gradient flex flex-col gap-2 lg:gap-0 lg:flex-row justify-between rounded-lg p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
12
+ <div class="gradient flex flex-col gap-2 lg:gap-0 lg:flex-row justify-between rounded-md p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
13
13
  <div>
14
- <p class="mb-2 font-semibold">
14
+ <p class="mb-2 text-h5">
15
15
  {{ t('modals.id.banners.auth.title') }}
16
16
  </p>
17
17
  <i18n-t
18
18
  keypath="modals.id.banners.auth.subtitle"
19
19
  tag="p"
20
- class="text-sm text-gray-600 dark:text-gray-200"
20
+ class="text-body-md text-gray-600 dark:text-gray-200"
21
21
  >
22
22
  <template #register>
23
23
  <button class="font-semibold text-blue-700 dark:text-blue-500" @click="onRegister">
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
2
  import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
3
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
4
+ import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
4
5
 
5
6
  const { $toast } = useNuxtApp()
6
7
  const { t, locale } = useI18n()
@@ -40,17 +41,11 @@ async function loginUser() {
40
41
  },
41
42
  })
42
43
  const { data: cookiesData } = await response.json()
43
- if (cookiesData) {
44
+ if (cookiesData?.access_token) {
44
45
  const { access_token, expire_in } = cookiesData
45
- const hostname = location.hostname.split('.').reverse()
46
46
  useCookie('autoLogout').value = true
47
47
 
48
- useCookie('accessToken', {
49
- maxAge: expire_in,
50
- domain: `.${hostname[1]}.${hostname[0]}`,
51
- path: '/',
52
- secure: true,
53
- }).value = access_token
48
+ await writeAccessTokenCookie(access_token, expire_in)
54
49
  }
55
50
  }
56
51
 
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
3
4
  import { navigateToLocalizedPage } from '#adata-ui/utils/localizedNavigation'
4
5
  import * as z from 'zod'
5
6
  import { useUrls } from '#adata-ui/composables/useUrls'
@@ -127,17 +128,11 @@ async function submit() {
127
128
  },
128
129
  })
129
130
  const { data: cookiesData } = await response.json()
130
- if (cookiesData) {
131
+ if (cookiesData?.access_token) {
131
132
  const { access_token, expire_in } = cookiesData
132
- const hostname = location.hostname.split('.').reverse()
133
133
  useCookie('autoLogout').value = true
134
134
 
135
- useCookie('accessToken', {
136
- maxAge: expire_in,
137
- domain: COOKIE_DOMAIN,
138
- path: '/',
139
- secure: true,
140
- }).value = access_token
135
+ await writeAccessTokenCookie(access_token, expire_in)
141
136
  }
142
137
  $toast.success(t('reuse.successfully'))
143
138
 
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
2
+ import IdAutoLogoutModal from '#adata-ui/components/modals/id/IdAutoLogoutModal.vue'
3
3
  import IdConfirmAccountOtpModal from '#adata-ui/components/modals/id/IdConfirmAccountOtpModal.vue'
4
4
  import IdConfirmSuccessfulModal from '#adata-ui/components/modals/id/IdConfirmSuccessfulModal.vue'
5
5
  import IdLoginModal from '#adata-ui/components/modals/id/IdLoginModal.vue'
@@ -9,7 +9,8 @@ import IdRecoveryModal from '#adata-ui/components/modals/id/IdRecoveryModal.vue'
9
9
  import IdRegistrationModal from '#adata-ui/components/modals/id/IdRegistrationModal.vue'
10
10
  import IdResetPasswordOtpModal from '#adata-ui/components/modals/id/IdResetPasswordOtpModal.vue'
11
11
  import IdTwoFactorModal from '#adata-ui/components/modals/id/IdTwoFactorModal.vue'
12
- import IdAutoLogoutModal from '#adata-ui/components/modals/id/IdAutoLogoutModal.vue'
12
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
13
+ import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
13
14
 
14
15
  const emit = defineEmits<{
15
16
  (e: 'closed', value: boolean): void
@@ -35,6 +36,10 @@ const authApiURL = commonAuth.authApiURL
35
36
  const accessToken = useCookie('accessToken')
36
37
  const isAuthenticated = computed(() => !!accessToken.value)
37
38
 
39
+ // one-shot флаг: обмен по auth-сессии перезагружает страницу максимум один раз,
40
+ // иначе нечитаемая кука accessToken зацикливает reload
41
+ const AUTH_RELOAD_FLAG = 'auth-exchange-reloaded'
42
+
38
43
  onMounted(async () => {
39
44
  const response = await fetch(`${removeTrailingSlash(authApiURL)}/access/cookie`, {
40
45
  method: 'GET',
@@ -46,17 +51,25 @@ onMounted(async () => {
46
51
  const { data: cookiesData } = await response.json()
47
52
  if (cookiesData?.access_token && !accessToken.value) {
48
53
  const { access_token, expire_in } = cookiesData
49
- const hostname = location.hostname.split('.').reverse()
50
54
  useCookie('autoLogout').value = true
51
55
 
52
- useCookie('accessToken', {
53
- maxAge: expire_in,
54
- domain: `.${hostname[1]}.${hostname[0]}`,
55
- path: '/',
56
- secure: true,
57
- }).value = access_token
56
+ const persisted = await writeAccessTokenCookie(access_token, expire_in)
58
57
 
59
- window.location.reload()
58
+ if (persisted && !sessionStorage.getItem(AUTH_RELOAD_FLAG)) {
59
+ sessionStorage.setItem(AUTH_RELOAD_FLAG, '1')
60
+ window.location.reload()
61
+ }
62
+ else {
63
+ sessionStorage.removeItem(AUTH_RELOAD_FLAG)
64
+ console.warn(
65
+ persisted
66
+ ? '[auth] accessToken cookie is erased between page loads (SSR resetTokens?), reload skipped to avoid a loop'
67
+ : '[auth] accessToken cookie was not persisted (domain/secure/maxAge rejected by browser), reload skipped',
68
+ )
69
+ }
70
+ }
71
+ else {
72
+ sessionStorage.removeItem(AUTH_RELOAD_FLAG)
60
73
  }
61
74
  })
62
75
 
@@ -83,7 +83,7 @@ onBeforeUnmount(() => {
83
83
 
84
84
  <template>
85
85
  <form
86
- class="flex flex-col items-stretch gap-5 rounded-lg text-center"
86
+ class="flex flex-col items-stretch gap-5 rounded-md text-center"
87
87
  novalidate
88
88
  @submit.prevent="onSubmit"
89
89
  >
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
2
  import IdOtpInput from '#adata-ui/components/modals/id/IdOtpInput.vue'
3
+ import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
4
+ import { writeAccessTokenCookie } from '#adata-ui/composables/useAccessTokenCookie'
4
5
  import { useUrls } from '#adata-ui/composables/useUrls'
5
6
 
6
7
  const { $toast } = useNuxtApp()
@@ -54,15 +55,9 @@ async function onConfirm() {
54
55
  const { data: cookiesData } = await response.json()
55
56
  if (cookiesData?.access_token) {
56
57
  const { access_token, expire_in } = cookiesData
57
- const hostname = location.hostname.split('.').reverse()
58
58
  useCookie('autoLogout').value = true
59
59
 
60
- useCookie('accessToken', {
61
- maxAge: expire_in,
62
- domain: `.${hostname[1]}.${hostname[0]}`,
63
- path: '/',
64
- secure: true,
65
- }).value = access_token
60
+ await writeAccessTokenCookie(access_token, expire_in)
66
61
  }
67
62
  $toast.success(t('login.successfully'))
68
63
  twoFactorModal.value = false
@@ -56,7 +56,7 @@ const profile: string = 'modals.mobile_navigation.type_profile'
56
56
  </script>
57
57
 
58
58
  <template>
59
- <header class="w-full border-t border-[#9DA3AC80] bg-white dark:bg-gray-900">
59
+ <header class="mx-3 mb-3 overflow-hidden rounded-full border border-deepblue-900/10 bg-gray-50/20 shadow-lg backdrop-blur-lg dark:border-gray-200/10 dark:bg-gray-900/30">
60
60
  <div class="grid w-full grid-cols-3 justify-items-center">
61
61
  <slot>
62
62
  <button
@@ -1,67 +1,128 @@
1
1
  <script lang="ts" setup>
2
2
  import type { Crumb } from './types'
3
- import { twMerge } from 'tailwind-merge'
3
+ import { twMerge } from '#adata-ui/utils/twMerge'
4
4
 
5
- defineProps<{
5
+ const props = defineProps<{
6
6
  links: Crumb[]
7
7
  customClasses?: string
8
+ collapsible?: boolean
8
9
  }>()
9
10
 
10
11
  const { t } = useI18n()
12
+
13
+ const expanded = ref(false)
14
+
15
+ type Item = { kind: 'crumb', crumb: Crumb, position: number } | { kind: 'ellipsis' }
16
+
17
+ const items = computed<Item[]>(() => {
18
+ const toItem = (crumb: Crumb, position: number): Item => ({ kind: 'crumb', crumb, position })
19
+
20
+ if (!props.collapsible || expanded.value || props.links.length <= 3) {
21
+ return props.links.map(toItem)
22
+ }
23
+
24
+ const last = props.links.length
25
+ return [
26
+ toItem(props.links[0], 0),
27
+ { kind: 'ellipsis' },
28
+ toItem(props.links[last - 2], last - 2),
29
+ toItem(props.links[last - 1], last - 1),
30
+ ]
31
+ })
11
32
  </script>
33
+
12
34
  <template>
13
- <div class="">
35
+ <div>
14
36
  <ul
15
- class="flex gap-1"
37
+ class="flex items-center gap-2"
16
38
  itemscope
17
39
  itemtype="https://schema.org/BreadcrumbList"
18
40
  >
19
- <li
20
- v-for="(breadcrumbItem, idx) in links"
21
- :key="idx"
22
- :class="
23
- twMerge(
24
- 'flex items-center text-xs text-gray-500 underline-offset-2 last-of-type:text-deepblue-900 hover:underline dark:last-of-type:text-gray-200',
25
- customClasses
26
- )
27
- "
28
- itemprop="itemListElement"
29
- itemscope
30
- itemtype="https://schema.org/ListItem"
41
+ <template
42
+ v-for="(item, idx) in items"
43
+ :key="item.kind === 'crumb' ? item.position : 'ellipsis'"
31
44
  >
32
- <meta
33
- itemprop="position"
34
- :content="`${idx}`"
35
- >
36
- <slot
37
- name="icon"
38
- :breadcrumb-item="breadcrumbItem"
39
- :index="idx"
45
+ <li
46
+ v-if="item.kind === 'ellipsis'"
47
+ class="flex items-center gap-2"
40
48
  >
41
- <span v-if="idx !== 0">
42
- <a-icon-chevron-right />
49
+ <span class="text-[#CAD5E2] dark:text-gray-600">
50
+ <a-icon-chevron-right class="size-4" />
43
51
  </span>
44
- </slot>
45
- <nuxt-link-locale
46
- v-if="breadcrumbItem.to"
47
- class="pl-1"
48
- :to="breadcrumbItem.to"
49
- rel="noopener noreferrer"
50
- itemprop="item"
51
- :data-test-id="breadcrumbItem?.dataTestId"
52
- >
53
- <span itemprop="name">
54
- {{ t(breadcrumbItem.label) }}
55
- </span>
56
- </nuxt-link-locale>
57
- <span
52
+ <button
53
+ type="button"
54
+ class="flex size-[18px] items-center justify-center rounded text-[#62748E] transition-colors hover:text-deepblue-900 dark:text-gray-400 dark:hover:text-gray-200"
55
+ :aria-label="t('actions.showMore')"
56
+ @click="expanded = true"
57
+ >
58
+ <a-icon-horizontal-more class="size-4" />
59
+ </button>
60
+ </li>
61
+ <li
58
62
  v-else
59
- class="pl-1"
60
- itemprop="name"
63
+ :class="
64
+ twMerge(
65
+ 'flex items-center gap-2 text-body-md text-[#62748E] underline-offset-2 last-of-type:font-semibold last-of-type:text-deepblue-900 hover:underline dark:text-gray-400 dark:last-of-type:text-gray-200',
66
+ customClasses,
67
+ )
68
+ "
69
+ itemprop="itemListElement"
70
+ itemscope
71
+ itemtype="https://schema.org/ListItem"
61
72
  >
62
- {{ t(breadcrumbItem.label) }}
63
- </span>
64
- </li>
73
+ <meta
74
+ itemprop="position"
75
+ :content="`${item.position}`"
76
+ >
77
+ <slot
78
+ name="icon"
79
+ :breadcrumb-item="item.crumb"
80
+ :index="idx"
81
+ >
82
+ <span
83
+ v-if="idx !== 0"
84
+ class="text-[#CAD5E2] dark:text-gray-600"
85
+ >
86
+ <a-icon-chevron-right class="size-4" />
87
+ </span>
88
+ </slot>
89
+ <nuxt-link-locale
90
+ v-if="item.crumb.to"
91
+ class="flex items-center"
92
+ :to="item.crumb.to"
93
+ rel="noopener noreferrer"
94
+ itemprop="item"
95
+ :data-test-id="item.crumb?.dataTestId"
96
+ :aria-label="item.crumb.icon ? t(item.crumb.label) : undefined"
97
+ >
98
+ <component
99
+ :is="item.crumb.icon"
100
+ v-if="item.crumb.icon"
101
+ class="size-[18px]"
102
+ />
103
+ <span
104
+ itemprop="name"
105
+ :class="item.crumb.icon ? 'sr-only' : ''"
106
+ >
107
+ {{ t(item.crumb.label) }}
108
+ </span>
109
+ </nuxt-link-locale>
110
+ <span
111
+ v-else
112
+ class="flex items-center"
113
+ itemprop="name"
114
+ >
115
+ <component
116
+ :is="item.crumb.icon"
117
+ v-if="item.crumb.icon"
118
+ class="size-[18px]"
119
+ />
120
+ <span :class="item.crumb.icon ? 'sr-only' : ''">
121
+ {{ t(item.crumb.label) }}
122
+ </span>
123
+ </span>
124
+ </li>
125
+ </template>
65
126
  </ul>
66
127
  </div>
67
128
  </template>
@@ -1,5 +1,8 @@
1
+ import type { Component } from 'vue'
2
+
1
3
  export interface Crumb {
2
4
  label: string
3
5
  to: string
4
6
  dataTestId?: string
7
+ icon?: Component
5
8
  }