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
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { PAGES } from '#adata-ui/shared/constans/pages'
2
+ import { useActiveNavigation } from '#adata-ui/composables/useActiveNavigation'
3
3
 
4
4
  interface NavList {
5
5
  title: string
@@ -18,61 +18,23 @@ const props = defineProps<{
18
18
  currentModule: boolean
19
19
  }>()
20
20
 
21
+ const { isActiveService } = useActiveNavigation()
22
+
21
23
  function isActive(itemPath: string) {
22
24
  if (!props.currentModule) return false
23
-
24
- const currentUrl = window.location.href.split('/').filter(item => !['kk', 'en'].includes(item)).join('/')
25
- const section = PAGES[props.id]
26
-
27
- const currentPath = itemPath.split('/').filter(item => !['kk', 'en'].includes(item)).join('/')
28
-
29
- if (currentUrl === currentPath) return true
30
-
31
- if (currentPath.endsWith('/')) {
32
- let atLeastOne = false
33
-
34
- for (const key in section) {
35
- const path = section[key]
36
- if (key !== 'main') {
37
- const includes = currentUrl.includes(path) || currentUrl.includes('car-result')
38
- if (includes) {
39
- atLeastOne = true
40
- break
41
- }
42
- }
43
- }
44
-
45
- return !atLeastOne
46
- }
47
-
48
- if (currentPath.includes('check-car')) {
49
- if (currentUrl.includes('car-result')) {
50
- return true
51
- }
52
- }
53
-
54
- for (const key in section) {
55
- const path = section[key]
56
- if (key !== 'main') {
57
- const includesBoth = currentUrl.includes(path) && currentUrl.startsWith(currentPath)
58
- if (includesBoth) {
59
- return true
60
- }
61
- }
62
- }
63
-
64
- return false
25
+ return isActiveService(itemPath)
65
26
  }
66
27
  </script>
67
28
 
68
29
  <template>
69
- <section class="group/section overflow-hidden rounded-xl border border-gray-200 bg-white p-3 shadow-sm transition-colors hover:border-blue-700/40 dark:border-gray-800 dark:bg-gray-950 dark:hover:border-blue-500/40">
30
+ <section class="group/section overflow-hidden flex flex-col ">
70
31
  <div class="mb-3 flex items-start justify-between gap-2">
71
32
  <nuxt-link-locale
72
33
  :to="link"
73
- class="group/title flex min-w-0 items-center gap-2 text-sm font-bold text-deepblue-900 transition-colors hover:text-blue-700 dark:text-gray-100 dark:hover:text-blue-500"
34
+ class="group/title flex min-w-0 items-center gap-2 text-base font-semibold text-deepblue-900 transition-colors hover:text-blue-700 dark:text-gray-100 dark:hover:text-blue-500"
74
35
  >
75
- <span class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-blue-700/10 text-blue-700 transition-colors group-hover/title:bg-blue-700 group-hover/title:text-white dark:bg-blue-500/10 dark:text-blue-500">
36
+ <span
37
+ class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-blue-50 text-blue-500 transition-colors group-hover/title:bg-blue-700 group-hover/title:text-white dark:bg-blue-500/10 dark:text-blue-500 dark:group-hover/title:bg-blue-500">
76
38
  <component
77
39
  :is="icon"
78
40
  class="size-4"
@@ -80,14 +42,6 @@ function isActive(itemPath: string) {
80
42
  </span>
81
43
  <span class="block truncate normal-case">{{ title }}</span>
82
44
  </nuxt-link-locale>
83
-
84
- <div class="flex shrink-0 items-center gap-1">
85
- <span
86
- v-if="badge"
87
- class="rounded-full bg-blue-700/10 px-1.5 py-0.5 text-[10px] font-bold uppercase leading-none text-blue-700 dark:bg-blue-500/10 dark:text-blue-500"
88
- >NEW</span>
89
- <a-icon-arrow-side-up class="size-4 text-gray-500 transition-colors group-hover/section:text-blue-700 dark:group-hover/section:text-blue-500" />
90
- </div>
91
45
  </div>
92
46
 
93
47
  <ul class="grid gap-1">
@@ -99,18 +53,20 @@ function isActive(itemPath: string) {
99
53
  v-if="item.to"
100
54
  :to="item.to"
101
55
  itemprop="name"
102
- class="group/item flex items-center gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-blue-100 dark:hover:bg-gray-200/10"
56
+ class="group/item flex items-center gap-2 rounded-lg px-2 py-1.5 transition-colors hover:bg-gray-50 dark:hover:bg-gray-200/10"
103
57
  :class="{ 'bg-blue-100 dark:bg-gray-200/10': isActive(item.to) }"
104
58
  >
105
- <span class="flex size-7 shrink-0 items-center justify-center rounded-md bg-gray-100 text-gray-600 transition-colors group-hover/item:bg-blue-700/10 group-hover/item:text-blue-700 dark:bg-gray-800 dark:text-gray-300 dark:group-hover/item:text-blue-500">
106
- <component
107
- :is="item.icon"
108
- class="size-[14px]"
109
- />
110
- </span>
111
- <span class="truncate text-sm font-semibold normal-case text-gray-600 transition-colors group-hover/item:text-deepblue-900 dark:text-gray-300 dark:group-hover/item:text-gray-100">{{ item.title }}</span>
59
+ <a-icon-chevron-right class="size-[14px] shrink-0 text-gray-300 group-hover/item:text-blue-500 dark:group-hover/item:text-blue-700" />
60
+ <span
61
+ class="min-w-0 text-sm normal-case transition-colors group-hover/item:text-deepblue-900 group-hover/item:font-semibold dark:group-hover/item:text-gray-100"
62
+ :class="isActive(item.to)
63
+ ? 'text-blue-700 dark:text-blue-500'
64
+ : 'text-gray-600 dark:text-gray-300'"
65
+ >{{ item.title }}</span>
112
66
  </nuxt-link-locale>
113
67
  </li>
114
68
  </ul>
69
+
70
+ <slot name="bottom" />
115
71
  </section>
116
72
  </template>
@@ -1,18 +1,21 @@
1
1
  <script setup lang="ts">
2
- import CardGallery from '#adata-ui/components/navigation/header/CardGallery.vue'
3
2
  import NavList from '#adata-ui/components/navigation/header/NavList.vue'
3
+ import { useActiveNavigation } from '#adata-ui/composables/useActiveNavigation'
4
4
  import { useHeaderNavigationLinks } from '#adata-ui/composables/useHeaderNavigationLinks'
5
+ import { PAGES } from '#adata-ui/shared/constans/pages'
6
+ import { useUrls } from '#adata-ui/composables/useUrls'
7
+ import AIconArrowRight from '#adata-ui/icons/arrow/arrow-right.vue'
8
+ import AIconDownloadRounded from '#adata-ui/icons/download-rounded.vue'
5
9
 
6
10
  defineProps<{ url?: string }>()
7
11
  defineEmits(['outerClick', 'mouseOver'])
8
12
 
9
- const { t } = useI18n()
13
+ const urls = useUrls()
14
+ const { t, locale } = useI18n()
10
15
  const modules = useHeaderNavigationLinks()
16
+ const { isActiveModule } = useActiveNavigation()
11
17
 
12
- // Fixed EDO promo card on the left (like edo-editor); EDO is excluded from the catalog grid below.
13
- const edoModule = computed(() => modules.value.find(module => module.key === 'edo') ?? null)
14
-
15
- const COLUMN_KEYS = [['pk', 'fines', 'work'], ['fea', 'tenders'], ['compliance', 'analytics']]
18
+ const COLUMN_KEYS = [['edo'], ['pk'], ['compliance', 'fines'], ['tenders', 'analytics'], ['fea', 'work']]
16
19
  const catalogColumns = computed(() =>
17
20
  COLUMN_KEYS.map(keys =>
18
21
  keys
@@ -20,6 +23,14 @@ const catalogColumns = computed(() =>
20
23
  .filter((module): module is NonNullable<typeof module> => module !== undefined),
21
24
  ),
22
25
  )
26
+
27
+ function handleExportClick() {
28
+ navigateToLocalizedPage({
29
+ locale: locale.value,
30
+ projectUrl: urls.pk,
31
+ path: PAGES.pk.unload,
32
+ })
33
+ }
23
34
  </script>
24
35
 
25
36
  <template>
@@ -27,54 +38,18 @@ const catalogColumns = computed(() =>
27
38
  <div class="relative bg-white dark:bg-gray-950">
28
39
  <div class="a-container max-h-[calc(100dvh-4rem)] overflow-y-auto overscroll-contain py-8">
29
40
  <div class="flex justify-between gap-5">
30
- <!-- Left sidebar: EDO promo card (edo-editor style) + promo carousel. -->
31
- <aside class="flex w-[320px] shrink-0 flex-col gap-5">
32
- <nuxt-link-locale
33
- v-if="edoModule"
34
- :to="edoModule.link"
35
- class="group block overflow-hidden rounded-xl border border-blue-700/20 bg-blue-50 p-4 shadow-sm transition-colors hover:border-blue-700/40 hover:bg-blue-100 dark:border-blue-500/20 dark:bg-blue-500/5 dark:hover:border-blue-500/40 dark:hover:bg-blue-500/10"
36
- :data-test-id="edoModule.data_attribute"
37
- >
38
- <div class="flex items-start gap-3">
39
- <div class="flex size-10 shrink-0 items-center justify-center rounded-lg bg-blue-700 text-white shadow-sm">
40
- <component
41
- :is="edoModule.icon"
42
- class="size-5"
43
- />
44
- </div>
45
- <div class="min-w-0">
46
- <div class="flex items-center gap-2">
47
- <h3 class="text-base font-bold normal-case text-deepblue-900 dark:text-gray-100">
48
- {{ edoModule.name }}
49
- </h3>
50
- <a-icon-arrow-side-up class="size-4 text-blue-700 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5 dark:text-blue-500" />
51
- </div>
52
- <p class="mt-1 text-sm normal-case leading-snug text-gray-600 dark:text-gray-300">
53
- {{ t('header.products.edo.heroSubtitle') }}
54
- </p>
55
- </div>
56
- </div>
57
- <div class="mt-4 inline-flex items-center gap-1.5 text-sm font-semibold normal-case text-blue-700 dark:text-blue-500">
58
- {{ t('header.products.edo.heroCta') }}
59
- <a-icon-arrow-side-up class="size-3.5" />
60
- </div>
61
- </nuxt-link-locale>
62
-
63
- <card-gallery class="hidden lg:block" />
64
- </aside>
65
-
66
- <!-- Catalog grid: products as bordered section cards (EDO lives in the hero). -->
67
- <div class="grid min-w-0 flex-1 grid-cols-3 gap-3">
41
+ <div class="grid min-w-0 flex-1 grid-cols-5 gap-x-3 gap-y-3">
68
42
  <div
69
43
  v-for="(column, index) in catalogColumns"
70
44
  :key="index"
71
- class="flex flex-col gap-3"
45
+ class="flex flex-col gap-[22px]"
46
+ :class="index > 0 ? 'border-l border-gray-100 pl-3 dark:border-gray-800' : ''"
72
47
  >
73
48
  <nav-list
74
49
  v-for="module in column"
75
50
  :id="module.key"
76
51
  :key="module.key"
77
- :current-module="false"
52
+ :current-module="isActiveModule(module)"
78
53
  :title="module.name"
79
54
  :link="module.link"
80
55
  :nav-list="module.items"
@@ -82,7 +57,40 @@ const catalogColumns = computed(() =>
82
57
  :icon="module.icon"
83
58
  :badge="module.is_new"
84
59
  :data-test-id="module.data_attribute"
85
- />
60
+ >
61
+ <template
62
+ v-if="module.key === 'edo'"
63
+ #bottom
64
+ >
65
+ <div class="mt-4 flex flex-col gap-4 rounded-xl bg-blue-700 dark:bg-blue-500 p-4 text-white normal-case">
66
+ <div class="flex items-center gap-3">
67
+ <span class="p-[10px] bg-white rounded-[10px] dark:bg-gray-950">
68
+ <AIconDownloadRounded class="size-5 text-blue-700 dark:text-blue-500" />
69
+ </span>
70
+ <span class="font-semibold text-white dark:text-gray-950">
71
+ {{ t('header.products.exportCard.title') }}
72
+ </span>
73
+ </div>
74
+
75
+ <div class="text-xs text-white dark:text-gray-950">
76
+ {{ t('header.products.exportCard.subTitle') }}
77
+ </div>
78
+
79
+ <a-button-v2
80
+ view="soft"
81
+ class="!h-9 w-fit !bg-white dark:!bg-gray-950 text-blue-700 dark:text-blue-500"
82
+ size="sm"
83
+ :icon="AIconArrowRight"
84
+ icon-right
85
+ @click="handleExportClick"
86
+ >
87
+ <span class="text-sm">
88
+ {{ t('header.products.exportCard.receive') }}
89
+ </span>
90
+ </a-button-v2>
91
+ </div>
92
+ </template>
93
+ </nav-list>
86
94
  </div>
87
95
  </div>
88
96
  </div>
@@ -0,0 +1,118 @@
1
+ <script lang="ts" setup>
2
+ type CountColor = 'gray' | 'blue' | 'yellow' | 'red' | 'green' | 'neutral'
3
+
4
+ export interface PillTab {
5
+ key: string
6
+ name: string
7
+ count?: number
8
+ countColor?: CountColor
9
+ disabled?: boolean
10
+ hideCount?: boolean
11
+ }
12
+
13
+ const props = withDefaults(defineProps<{
14
+ modelValue: string
15
+ options: PillTab[]
16
+ showCount?: boolean
17
+ ariaLabel?: string
18
+ block?: boolean
19
+ disabled?: boolean
20
+ size?: 'sm' | 'md'
21
+ }>(), {
22
+ showCount: false,
23
+ block: false,
24
+ disabled: false,
25
+ size: 'sm',
26
+ })
27
+
28
+ const emit = defineEmits<{ (e: 'update:modelValue', value: string): void }>()
29
+
30
+ const SIZE_CLASS: Record<'sm' | 'md', string> = {
31
+ sm: 'text-xs',
32
+ md: 'text-sm',
33
+ }
34
+
35
+ const COUNT_COLOR_CLASS: Record<CountColor, string> = {
36
+ gray: 'bg-gray-200/70 text-gray-600 dark:bg-white/[0.08] dark:text-gray-300',
37
+ blue: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300',
38
+ yellow: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/40 dark:text-yellow-300',
39
+ red: 'bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-300',
40
+ green: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300',
41
+ neutral: 'bg-gray-100 text-gray-500 dark:bg-white/[0.06] dark:text-gray-400',
42
+ }
43
+
44
+ const { t, te } = useI18n()
45
+
46
+ function localize(label: string) {
47
+ return te(label) ? t(label) : label
48
+ }
49
+
50
+ function isDisabled(option: PillTab) {
51
+ return props.disabled || option.disabled === true
52
+ }
53
+
54
+ function select(option: PillTab) {
55
+ if (isDisabled(option)) return
56
+ emit('update:modelValue', option.key)
57
+ }
58
+ </script>
59
+
60
+ <template>
61
+ <div
62
+ class="pill-tabs-v2 min-w-0 max-w-full rounded-xl border border-gray-200 bg-gray-50 p-1 dark:border-white/10 dark:bg-white/[0.03]"
63
+ :class="[
64
+ block ? 'w-full' : 'w-fit',
65
+ disabled ? 'pill-tabs-v2--disabled opacity-60' : '',
66
+ ]"
67
+ :aria-disabled="disabled || undefined"
68
+ >
69
+ <div
70
+ role="tablist"
71
+ :aria-label="ariaLabel"
72
+ class="pill-tabs-v2__list flex w-full flex-nowrap items-center gap-1 overflow-x-auto"
73
+ >
74
+ <button
75
+ v-for="option in options"
76
+ :key="option.key"
77
+ type="button"
78
+ role="tab"
79
+ :aria-selected="modelValue === option.key"
80
+ :aria-disabled="isDisabled(option) || undefined"
81
+ :disabled="isDisabled(option)"
82
+ :tabindex="modelValue === option.key ? 0 : -1"
83
+ class="inline-flex items-center gap-1.5 whitespace-nowrap rounded-lg px-3 py-1.5 font-medium transition-colors duration-150"
84
+ :class="[
85
+ SIZE_CLASS[size],
86
+ isDisabled(option)
87
+ ? 'cursor-not-allowed text-gray-300 dark:text-gray-600'
88
+ : modelValue === option.key
89
+ ? 'text-deepblue-900 bg-white shadow-sm dark:bg-gray-700 dark:text-gray-100 dark:shadow-none dark:ring-1 dark:ring-inset dark:ring-white/10'
90
+ : 'text-gray-700 hover:bg-white/70 hover:text-gray-900 dark:text-gray-200 dark:hover:bg-white/[0.06] dark:hover:text-gray-100',
91
+ block ? 'flex-1 basis-0 justify-center' : 'shrink-0',
92
+ ]"
93
+ @click="select(option)"
94
+ >
95
+ <slot name="option" :option="option">
96
+ <span>{{ localize(option.name) }}</span>
97
+
98
+ <span
99
+ v-if="showCount && !option.hideCount"
100
+ class="inline-flex min-w-5 shrink-0 items-center justify-center rounded-full px-1.5 text-xs font-semibold leading-5"
101
+ :class="COUNT_COLOR_CLASS[option.countColor ?? 'gray']"
102
+ >
103
+ {{ option.count }}
104
+ </span>
105
+ </slot>
106
+ </button>
107
+ </div>
108
+ </div>
109
+ </template>
110
+
111
+ <style scoped>
112
+ .pill-tabs-v2__list {
113
+ scrollbar-width: none;
114
+ }
115
+ .pill-tabs-v2__list::-webkit-scrollbar {
116
+ display: none;
117
+ }
118
+ </style>