adata-ui 2.1.40-beta.4 → 2.1.40-beta.6

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 (35) hide show
  1. package/components/elements/a-select-row/ASelectRowV2.vue +5 -4
  2. package/components/elements/button/AButtonV2.vue +29 -6
  3. package/components/elements/select/ASelectV2.vue +17 -9
  4. package/components/elements/status-badge-v2/StatusBadgeV2.vue +78 -0
  5. package/components/forms/feedback-form/FeedbackForm.vue +8 -8
  6. package/components/forms/input/AInputV2.vue +1 -1
  7. package/components/forms/input/textarea/ATextareaV2.vue +248 -0
  8. package/components/modals/AnotherDeviceModal.vue +16 -17
  9. package/components/modals/ApplicationAcceptedModal.vue +12 -15
  10. package/components/modals/ConnectingTariffModal.vue +13 -20
  11. package/components/modals/Insufficient-funds-modal.vue +18 -33
  12. package/components/modals/LimitReachedModal.vue +4 -3
  13. package/components/modals/NoAccessModal.vue +9 -11
  14. package/components/modals/PaymentMethodModal.vue +1 -1
  15. package/components/modals/ReportBugConfirmModal.vue +12 -10
  16. package/components/modals/ReportBugModal.vue +42 -36
  17. package/components/modals/Resend.vue +9 -10
  18. package/components/modals/SubmitApplicationModal.vue +27 -24
  19. package/components/navigation/header/HeaderLink.vue +15 -21
  20. package/components/navigation/header/NavList.vue +8 -32
  21. package/components/navigation/header/ProductMenu.vue +52 -50
  22. package/components/overlays/modal/AModalV2.vue +10 -9
  23. package/composables/useChipOverflow.ts +17 -7
  24. package/composables/useHeaderNavigationLinks.ts +53 -23
  25. package/icons/arrow/arrow-right.vue +14 -0
  26. package/icons/briefcase.vue +14 -0
  27. package/icons/car-side.vue +16 -0
  28. package/icons/cart.vue +15 -0
  29. package/icons/download-rounded.vue +15 -0
  30. package/icons/shield-verified.vue +14 -0
  31. package/lang/en.ts +34 -4
  32. package/lang/kk.ts +34 -4
  33. package/lang/ru.ts +36 -6
  34. package/package.json +1 -1
  35. package/shared/constans/pages.ts +8 -2
@@ -22,18 +22,18 @@ interface HeaderNav {
22
22
 
23
23
  const navs: HeaderNav[] = [
24
24
  { label: 'header.navs.products', dataAttribute: 'header-products-and-solutions-button', menu: ProductMenu },
25
- { label: 'header.navs.contacts', dataAttribute: 'header-contacts-button', menu: ContactMenu },
25
+ { label: 'header.navs.contacts', dataAttribute: 'header-contacts-button' },
26
26
  { label: 'header.navs.tariffs', dataAttribute: 'header-tariffs-button' },
27
27
  ]
28
28
 
29
- const OPEN_DELAY = 500 // hover dwell before opening, so a pass-through doesn't trigger it
30
- const SWITCH_DELAY = 80 // snappier when moving between items with the menu already open
29
+ const OPEN_DELAY = 500
30
+ const SWITCH_DELAY = 80
31
31
 
32
32
  const menu = ref<HTMLElement | null>(null)
33
33
  const show = ref(false)
34
- const locked = ref(false) // a click pins the menu; hover can no longer close it
34
+ const locked = ref(false)
35
35
  const currentIndex = ref(0)
36
- const swapName = ref('swap-fade') // panel transition: directional slide on switch, fade on fresh open
36
+ const swapName = ref('swap-fade')
37
37
  const hoverTimer = ref<ReturnType<typeof setTimeout> | null>(null)
38
38
 
39
39
  const currentMenu = computed(() => navs[currentIndex.value]?.menu ?? null)
@@ -42,8 +42,6 @@ function isActive(index: number) {
42
42
  return show.value && currentIndex.value === index
43
43
  }
44
44
 
45
- // Open `index`'s panel. Slide toward the direction of travel when switching
46
- // between already-open panels; fade (no sideways shift) on a fresh open.
47
45
  function openMenu(index: number) {
48
46
  swapName.value = show.value && index !== currentIndex.value
49
47
  ? (index > currentIndex.value ? 'slide-next' : 'slide-prev')
@@ -57,6 +55,10 @@ function closeMenu() {
57
55
  locked.value = false
58
56
  }
59
57
 
58
+ function goToContacts() {
59
+ navigateToLocalizedPage({ locale, projectUrl: landing, path: PAGES.contacts, target: '_blank' })
60
+ }
61
+
60
62
  function goToTariffs() {
61
63
  const host = useRequestURL().hostname
62
64
  const codeMap: Record<string, string> = {
@@ -73,11 +75,15 @@ function goToTariffs() {
73
75
  navigateToLocalizedPage({ locale, projectUrl: landing, path: PAGES.tariffs + code, target: '_blank' })
74
76
  }
75
77
 
76
- // Click pins the menu open; items without a menu (Tariffs) navigate instead.
77
78
  function toggleMenu(index: number) {
78
79
  const nav = navs[index]
79
80
  if (!nav?.menu) {
80
- goToTariffs()
81
+ if (index === 1) {
82
+ goToContacts()
83
+ }
84
+ else if (index === 2) {
85
+ goToTariffs()
86
+ }
81
87
  return
82
88
  }
83
89
  if (show.value && currentIndex.value === index) {
@@ -95,7 +101,6 @@ function clearHoverTimer() {
95
101
  }
96
102
  }
97
103
 
98
- // Hover opens menu items; hovering Tariffs dismisses an unpinned menu.
99
104
  function scheduleOpen(index: number) {
100
105
  clearHoverTimer()
101
106
  hoverTimer.value = setTimeout(() => {
@@ -104,14 +109,10 @@ function scheduleOpen(index: number) {
104
109
  }, show.value ? SWITCH_DELAY : OPEN_DELAY)
105
110
  }
106
111
 
107
- // Overlay closes on click regardless of the pin; on hover only while unpinned.
108
112
  function onOverlayHover() {
109
113
  if (!locked.value) closeMenu()
110
114
  }
111
115
 
112
- // Lock body scroll while the mega-menu is open. `scrollbar-gutter: stable` is set
113
- // globally, so we don't reserve the gap to avoid a double-compensated page shift.
114
- // The panel is mounted via v-if, so wait a tick for the ref on open.
115
116
  watch(show, async (open) => {
116
117
  if (open) {
117
118
  await nextTick()
@@ -157,7 +158,6 @@ onBeforeUnmount(() => {
157
158
  </li>
158
159
  </ul>
159
160
 
160
- <!-- One transition drives the whole panel's open/close (appear + disappear). -->
161
161
  <transition name="menu">
162
162
  <div
163
163
  v-if="show"
@@ -165,14 +165,12 @@ onBeforeUnmount(() => {
165
165
  class="fixed inset-x-0 z-20"
166
166
  :style="{ top: `${menuTop}px`, height: `calc(100dvh - ${menuTop}px)` }"
167
167
  >
168
- <!-- Full-page dimmed blur backdrop behind the panel. -->
169
168
  <div
170
169
  class="absolute inset-0 bg-gray-900/30 backdrop-blur dark:bg-black/50"
171
170
  @click="closeMenu"
172
171
  @mouseover="onOverlayHover"
173
172
  />
174
173
 
175
- <!-- Panel on top; slides left/right when switching between menu items. -->
176
174
  <transition
177
175
  :name="swapName"
178
176
  mode="out-in"
@@ -181,7 +179,6 @@ onBeforeUnmount(() => {
181
179
  :is="currentMenu"
182
180
  :key="currentIndex"
183
181
  class="relative"
184
- :url="buildLocalizedUrl(locale, landing, PAGES.contacts)"
185
182
  />
186
183
  </transition>
187
184
  </div>
@@ -193,7 +190,6 @@ onBeforeUnmount(() => {
193
190
  $ease: cubic-bezier(0.22, 1, 0.36, 1);
194
191
  $shift: 24px;
195
192
 
196
- // Whole menu: open and close (vertical fade, no horizontal motion).
197
193
  .menu-enter-active,
198
194
  .menu-leave-active {
199
195
  transition:
@@ -207,7 +203,6 @@ $shift: 24px;
207
203
  transform: translateY(-12px);
208
204
  }
209
205
 
210
- // Switching panels: slide toward the direction of travel (out-in, so no overlap).
211
206
  .slide-next-enter-active,
212
207
  .slide-next-leave-active,
213
208
  .slide-prev-enter-active,
@@ -239,7 +234,6 @@ $shift: 24px;
239
234
  transform: translateX($shift);
240
235
  }
241
236
 
242
- // Fresh open (no switch): fade only, so the panel never slides sideways.
243
237
  .swap-fade-enter-from,
244
238
  .swap-fade-leave-to {
245
239
  opacity: 0;
@@ -27,19 +27,14 @@ function isActive(itemPath: string) {
27
27
  </script>
28
28
 
29
29
  <template>
30
- <section
31
- class="group/section overflow-hidden rounded-xl border p-3 shadow-sm transition-colors"
32
- :class="currentModule
33
- ? 'border-blue-700/20 bg-blue-50 hover:border-blue-700/40 dark:border-blue-500/20 dark:bg-blue-500/5 dark:hover:border-blue-500/40'
34
- : 'border-gray-200 bg-white hover:border-blue-700/40 dark:border-gray-800 dark:bg-gray-950 dark:hover:border-blue-500/40'"
35
- >
30
+ <section class="group/section overflow-hidden flex flex-col ">
36
31
  <div class="mb-3 flex items-start justify-between gap-2">
37
32
  <nuxt-link-locale
38
33
  :to="link"
39
- 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"
40
35
  >
41
36
  <span
42
- 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">
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">
43
38
  <component
44
39
  :is="icon"
45
40
  class="size-4"
@@ -47,15 +42,6 @@ function isActive(itemPath: string) {
47
42
  </span>
48
43
  <span class="block truncate normal-case">{{ title }}</span>
49
44
  </nuxt-link-locale>
50
-
51
- <div class="flex shrink-0 items-center gap-1">
52
- <span
53
- v-if="badge"
54
- 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"
55
- >NEW</span>
56
- <a-icon-arrow-side-up
57
- class="size-4 text-gray-500 transition-colors group-hover/section:text-blue-700 dark:group-hover/section:text-blue-500"/>
58
- </div>
59
45
  </div>
60
46
 
61
47
  <ul class="grid gap-1">
@@ -67,24 +53,12 @@ function isActive(itemPath: string) {
67
53
  v-if="item.to"
68
54
  :to="item.to"
69
55
  itemprop="name"
70
- 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"
71
57
  :class="{ 'bg-blue-100 dark:bg-gray-200/10': isActive(item.to) }"
72
58
  >
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" />
73
60
  <span
74
- class="flex size-7 shrink-0 items-center justify-center rounded-md transition-colors group-hover/item:bg-blue-700/10 group-hover/item:text-blue-700 dark:group-hover/item:text-blue-500"
75
- :class="{
76
- 'bg-blue-700/10 text-blue-700 dark:bg-blue-500/10 dark:text-blue-500': isActive(item.to),
77
- 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-300': !isActive(item.to),
78
- // 'bg-white text-gray-600 dark:bg-white dark:text-gray-300': currentModule,
79
- }"
80
- >
81
- <component
82
- :is="item.icon"
83
- class="size-[14px]"
84
- />
85
- </span>
86
- <span
87
- class="truncate text-sm font-semibold normal-case transition-colors group-hover/item:text-deepblue-900 dark:group-hover/item:text-gray-100"
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"
88
62
  :class="isActive(item.to)
89
63
  ? 'text-blue-700 dark:text-blue-500'
90
64
  : 'text-gray-600 dark:text-gray-300'"
@@ -92,5 +66,7 @@ function isActive(itemPath: string) {
92
66
  </nuxt-link-locale>
93
67
  </li>
94
68
  </ul>
69
+
70
+ <slot name="bottom" />
95
71
  </section>
96
72
  </template>
@@ -1,20 +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'
4
3
  import { useActiveNavigation } from '#adata-ui/composables/useActiveNavigation'
5
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'
6
9
 
7
10
  defineProps<{ url?: string }>()
8
11
  defineEmits(['outerClick', 'mouseOver'])
9
12
 
10
- const { t } = useI18n()
13
+ const urls = useUrls()
14
+ const { t, locale } = useI18n()
11
15
  const modules = useHeaderNavigationLinks()
12
16
  const { isActiveModule } = useActiveNavigation()
13
17
 
14
- // Fixed EDO promo card on the left (like edo-editor); EDO is excluded from the catalog grid below.
15
- const edoModule = computed(() => modules.value.find(module => module.key === 'edo') ?? null)
16
-
17
- const COLUMN_KEYS = [['pk', 'fines', 'work'], ['fea', 'tenders'], ['compliance', 'analytics']]
18
+ const COLUMN_KEYS = [['edo'], ['pk'], ['compliance', 'fines'], ['tenders', 'analytics'], ['fea', 'work']]
18
19
  const catalogColumns = computed(() =>
19
20
  COLUMN_KEYS.map(keys =>
20
21
  keys
@@ -22,6 +23,14 @@ const catalogColumns = computed(() =>
22
23
  .filter((module): module is NonNullable<typeof module> => module !== undefined),
23
24
  ),
24
25
  )
26
+
27
+ function handleExportClick() {
28
+ navigateToLocalizedPage({
29
+ locale: locale.value,
30
+ projectUrl: urls.pk,
31
+ path: PAGES.pk.unload,
32
+ })
33
+ }
25
34
  </script>
26
35
 
27
36
  <template>
@@ -29,52 +38,12 @@ const catalogColumns = computed(() =>
29
38
  <div class="relative bg-white dark:bg-gray-950">
30
39
  <div class="a-container max-h-[calc(100dvh-4rem)] overflow-y-auto overscroll-contain py-8">
31
40
  <div class="flex justify-between gap-5">
32
- <!-- Left sidebar: EDO promo card (edo-editor style) + promo carousel. -->
33
- <aside class="flex w-[320px] shrink-0 flex-col gap-5">
34
- <nuxt-link-locale
35
- v-if="edoModule"
36
- :to="edoModule.link"
37
- class="group block overflow-hidden rounded-xl border border-blue-700/20 p-4 shadow-sm transition-colors hover:border-blue-700/40 hover:bg-blue-100 dark:border-blue-500/20 dark:hover:border-blue-500/40 dark:hover:bg-blue-500/10"
38
- :data-test-id="edoModule.data_attribute"
39
- >
40
- <div class="flex items-start gap-3">
41
- <div
42
- class="flex size-10 shrink-0 items-center justify-center rounded-lg bg-blue-700 text-white shadow-sm">
43
- <component
44
- :is="edoModule.icon"
45
- class="size-5"
46
- />
47
- </div>
48
- <div class="min-w-0">
49
- <div class="flex items-center justify-between gap-2">
50
- <h3 class="text-base font-bold normal-case text-deepblue-900 dark:text-gray-100">
51
- {{ edoModule.name }}
52
- </h3>
53
- <div class="flex items-center gap-1 justify-end">
54
- <span
55
- v-if="edoModule.is_new"
56
- 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"
57
- >NEW</span>
58
- <a-icon-arrow-side-up
59
- class="size-4 text-gray-500 transition group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-blue-700 dark:text-gray-400 dark:group-hover:text-blue-500"/>
60
- </div>
61
- </div>
62
- <p class="mt-1 text-sm normal-case leading-snug text-gray-600 dark:text-gray-300">
63
- {{ t('header.products.edo.heroSubtitle') }}
64
- </p>
65
- </div>
66
- </div>
67
- </nuxt-link-locale>
68
-
69
- <card-gallery class="hidden lg:block"/>
70
- </aside>
71
-
72
- <!-- Catalog grid: products as bordered section cards (EDO lives in the hero). -->
73
- <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">
74
42
  <div
75
43
  v-for="(column, index) in catalogColumns"
76
44
  :key="index"
77
- 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' : ''"
78
47
  >
79
48
  <nav-list
80
49
  v-for="module in column"
@@ -88,7 +57,40 @@ const catalogColumns = computed(() =>
88
57
  :icon="module.icon"
89
58
  :badge="module.is_new"
90
59
  :data-test-id="module.data_attribute"
91
- />
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>
92
94
  </div>
93
95
  </div>
94
96
  </div>
@@ -298,7 +298,7 @@ function onTouchEnd() {
298
298
  </div>
299
299
 
300
300
  <header
301
- v-if="!hideHeader && (title || $slots.header)"
301
+ v-if="!hideHeader"
302
302
  class="flex shrink-0 items-center justify-between gap-3 border-b border-gray-200 px-5 py-4 dark:border-gray-800"
303
303
  @touchstart.passive="onTouchStart"
304
304
  @touchmove="onTouchMove"
@@ -306,17 +306,18 @@ function onTouchEnd() {
306
306
  @touchcancel="onTouchEnd"
307
307
  >
308
308
  <slot name="header">
309
- <h2 class="text-base font-semibold text-gray-900 dark:text-gray-100">
309
+ <h2 v-if="title" class="text-base font-semibold text-gray-900 dark:text-gray-100">
310
310
  {{ title }}
311
311
  </h2>
312
- <button
313
- type="button"
314
- class="rounded-md p-1 text-gray-500 transition hover:bg-gray-100 hover:text-gray-700 dark:hover:bg-gray-800 dark:hover:text-gray-200"
315
- @click="closeIfAllowed"
316
- >
317
- <a-icon-x-mark class="size-4" />
318
- </button>
319
312
  </slot>
313
+ <!-- Кнопка закрытия не зависит от title и слота header — рендерится всегда (если header не скрыт). -->
314
+ <button
315
+ type="button"
316
+ class="ml-auto rounded-md p-1 text-gray-500 transition hover:bg-gray-100 hover:text-gray-700 dark:hover:bg-gray-800 dark:hover:text-gray-200"
317
+ @click="closeIfAllowed"
318
+ >
319
+ <a-icon-x-mark class="size-4" />
320
+ </button>
320
321
  </header>
321
322
 
322
323
  <div class="min-h-0 flex-1 overflow-auto" :class="contentClass">
@@ -4,6 +4,7 @@ interface UseChipOverflowOptions {
4
4
  container: Ref<HTMLElement | null>
5
5
  measure: Ref<HTMLElement | null>
6
6
  count: Ref<number>
7
+ contentKey?: Ref<unknown>
7
8
  gap?: number
8
9
  }
9
10
 
@@ -13,11 +14,17 @@ interface UseChipOverflow {
13
14
  }
14
15
 
15
16
  export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflow {
16
- const { container, measure, count, gap = 6 } = options
17
+ const { container, measure, count, contentKey, gap = 6 } = options
17
18
 
18
19
  const availableWidth = ref(0)
19
20
  const visibleCount = ref(0)
20
21
 
22
+ // Ceil so a chip is only counted as fitting when it fully fits;
23
+ // sub-pixel underestimates would let flexbox squeeze visible chips into truncation.
24
+ function chipWidth(el: HTMLElement): number {
25
+ return Math.ceil(el.getBoundingClientRect().width)
26
+ }
27
+
21
28
  function recompute() {
22
29
  const total = count.value
23
30
  if (total <= 0) {
@@ -38,7 +45,7 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
38
45
  let used = 0
39
46
  let fit = 0
40
47
  for (let i = 0; i < chips.length; i++) {
41
- const width = chips[i].offsetWidth + (i > 0 ? gap : 0)
48
+ const width = chipWidth(chips[i]) + (i > 0 ? gap : 0)
42
49
  if (used + width > avail) break
43
50
  used += width
44
51
  fit++
@@ -50,9 +57,9 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
50
57
  }
51
58
 
52
59
  const badge = root.children[total] as HTMLElement | undefined
53
- const badgeWidth = (badge?.offsetWidth ?? 0) + gap
60
+ const badgeWidth = (badge ? chipWidth(badge) : 0) + gap
54
61
  while (fit > 1 && used + badgeWidth > avail) {
55
- used -= chips[fit - 1].offsetWidth + gap
62
+ used -= chipWidth(chips[fit - 1]) + gap
56
63
  fit--
57
64
  }
58
65
 
@@ -63,9 +70,9 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
63
70
 
64
71
  onMounted(() => {
65
72
  if (container.value) {
66
- availableWidth.value = container.value.clientWidth
73
+ availableWidth.value = Math.floor(container.value.clientWidth)
67
74
  resizeObserver = new ResizeObserver((entries) => {
68
- availableWidth.value = entries[0]?.contentRect.width ?? 0
75
+ availableWidth.value = Math.floor(entries[0]?.contentRect.width ?? 0)
69
76
  })
70
77
  resizeObserver.observe(container.value)
71
78
  }
@@ -74,7 +81,10 @@ export function useChipOverflow(options: UseChipOverflowOptions): UseChipOverflo
74
81
 
75
82
  onUnmounted(() => resizeObserver?.disconnect())
76
83
 
77
- watch([availableWidth, count], () => nextTick(recompute))
84
+ watch(
85
+ contentKey ? [availableWidth, count, contentKey] : [availableWidth, count],
86
+ () => nextTick(recompute),
87
+ )
78
88
 
79
89
  const hiddenCount = computed(() => Math.max(0, count.value - visibleCount.value))
80
90
 
@@ -9,12 +9,9 @@ import IconBlock from '#adata-ui/icons/block.vue'
9
9
  import IconDollar from '#adata-ui/icons/currency/currency-dollar.vue'
10
10
  import IconWork from '#adata-ui/icons/work-bag.vue'
11
11
  import IconDocument from '#adata-ui/icons/hdocument.vue'
12
- import IconCheck from '#adata-ui/icons/hcheck.vue'
13
- import IconFile from '#adata-ui/icons/file/file.vue'
14
12
  import IconCheckCircle from '#adata-ui/icons/check/check-circle.vue'
15
13
  import IconCar from '#adata-ui/icons/car.vue'
16
14
  import IconTruck from '#adata-ui/icons/truck.vue'
17
- import IconClipboardText from '#adata-ui/icons/clipboard-text.vue'
18
15
  import IconArrowGraph from '#adata-ui/icons/arrow/arrow-graph-up.vue'
19
16
  import IconMedal from '#adata-ui/icons/medal.vue'
20
17
  import IconCompany from '#adata-ui/icons/company.vue'
@@ -26,24 +23,27 @@ import { buildLocalizedUrl } from '#adata-ui/utils/localizedNavigation'
26
23
  import IconLock from '#adata-ui/icons/lock.vue'
27
24
  import IconReceipt from '#adata-ui/icons/receipt.vue'
28
25
  import IconFavorite from '#adata-ui/icons/bookmark/bookmark.vue'
29
- // import IconReport from '#adata-ui/icons/file/file.vue'
30
26
  import IconHistory from '#adata-ui/icons/history.vue'
31
27
  import IconMessage from '#adata-ui/icons/message/message.vue'
28
+ import AIconBriefcase from '#adata-ui/icons/briefcase.vue'
29
+ import AIconCarSide from '#adata-ui/icons/car-side.vue'
30
+ import AIconShieldVerified from '#adata-ui/icons/shield-verified.vue'
31
+ import AIconCart from '#adata-ui/icons/cart.vue'
32
32
  import {
33
- AIconWorkBag,
34
33
  AIconUsersThree,
35
- AIconReceipt,
36
- AIconCar,
37
34
  AIconArrowGraphUp,
38
35
  AIconGlobe,
39
- AIconId,
40
- AIconFiles,
41
- AIconArrowSquareDown, AIconExpandWindow, AIconUsers, AIconWarningTriangle, AIconSearch, AIconAkimat, AIconCurrencyTenge, AIconExcelIcon
36
+ AIconArrowSquareDown,
37
+ AIconExpandWindow,
38
+ AIconUsers,
39
+ AIconWarningTriangle,
40
+ AIconSearch,
41
+ AIconAkimat,
42
+ AIconCurrencyTenge,
43
+ AIconExcelIcon,
42
44
  } from '#components'
43
45
  import MapPinRect from '#adata-ui/icons/map/map-pin-rect.vue'
44
46
  import MapPaper from '#adata-ui/icons/map-paper.vue'
45
- import ChartBar from '#adata-ui/icons/chart-bar.vue'
46
- import Bank from '#adata-ui/icons/bank.vue'
47
47
  import { useUrls } from '#adata-ui/composables/useUrls'
48
48
  import AiAssistant from '#adata-ui/icons/ai-assistant.vue'
49
49
  import Tasks from '#adata-ui/icons/tasks.vue'
@@ -61,7 +61,7 @@ export const useHeaderNavigationLinks = () => {
61
61
  key: 'pk',
62
62
  name: t('header.products.counterparties.label'),
63
63
  link: buildLocalizedUrl(locale, urls.pk, PAGES.pk.main),
64
- icon: AIconUsersThree,
64
+ icon: AIconUsers,
65
65
  to: urls.pk,
66
66
  data_attribute: 'navigation-menu-counterparty-block',
67
67
  items: [
@@ -115,7 +115,7 @@ export const useHeaderNavigationLinks = () => {
115
115
  key: 'fines',
116
116
  name: t('header.products.fines.label'),
117
117
  link: buildLocalizedUrl(locale, urls.avto, PAGES.fines.main),
118
- icon: AIconCar,
118
+ icon: AIconCarSide,
119
119
  data_attribute: 'navigation-menu-fines-block',
120
120
  items: [
121
121
  {
@@ -142,7 +142,7 @@ export const useHeaderNavigationLinks = () => {
142
142
  key: 'work',
143
143
  name: t('header.products.jobs.label'),
144
144
  link: urls.work,
145
- icon: AIconWorkBag,
145
+ icon: AIconBriefcase,
146
146
  data_attribute: 'navigation-menu-work-block',
147
147
  items: [
148
148
  {
@@ -216,7 +216,7 @@ export const useHeaderNavigationLinks = () => {
216
216
  key: 'tenders',
217
217
  name: t('header.products.tenders.label'),
218
218
  link: urls.zakupki,
219
- icon: AIconReceipt,
219
+ icon: AIconCart,
220
220
  is_new: true,
221
221
  to: urls.tender,
222
222
  data_attribute: 'navigation-menu-zakupki-block',
@@ -264,15 +264,39 @@ export const useHeaderNavigationLinks = () => {
264
264
  is_new: true,
265
265
  name: t('header.products.edo.label'),
266
266
  link: buildLocalizedUrl(locale, urls.edo_docs , ''),
267
- icon: AIconFiles,
267
+ icon: AIconUsers,
268
268
  data_attribute: 'navigation-menu-edo-block',
269
269
  items: [
270
270
  {
271
- title: t('header.products.edo.items.l.t'),
272
- subtitle: t('header.products.edo.items.l.t'),
273
- icon: AIconFiles,
274
- to: buildLocalizedUrl(locale, urls.edo_docs , '')
275
- }
271
+ title: t('header.products.edo.items.docSign.t'),
272
+ subtitle: t('header.products.edo.items.docSign.st'),
273
+ icon: AIconUsers,
274
+ to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docSign)
275
+ },
276
+ {
277
+ title: t('header.products.edo.items.docTemplate.t'),
278
+ subtitle: t('header.products.edo.items.docTemplate.st'),
279
+ icon: AIconUsers,
280
+ to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docTemplate)
281
+ },
282
+ {
283
+ title: t('header.products.edo.items.docRisk.t'),
284
+ subtitle: t('header.products.edo.items.docRisk.st'),
285
+ icon: AIconUsers,
286
+ to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docRisk)
287
+ },
288
+ {
289
+ title: t('header.products.edo.items.docCompare.t'),
290
+ subtitle: t('header.products.edo.items.docCompare.st'),
291
+ icon: AIconUsers,
292
+ to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docCompare)
293
+ },
294
+ {
295
+ title: t('header.products.edo.items.docAi.t'),
296
+ subtitle: t('header.products.edo.items.docAi.st'),
297
+ icon: AIconUsers,
298
+ to: buildLocalizedUrl(locale, urls.edo_docs , PAGES.edo.docAi)
299
+ },
276
300
  ]
277
301
  },
278
302
  {
@@ -280,7 +304,7 @@ export const useHeaderNavigationLinks = () => {
280
304
  is_new: true,
281
305
  name: t('header.products.compliance.label'),
282
306
  link: buildLocalizedUrl(locale, urls.compliance, PAGES.compliance.l),
283
- icon: AIconId,
307
+ icon: AIconShieldVerified,
284
308
  data_attribute: 'navigation-menu-compliance-block',
285
309
  items: [
286
310
  {
@@ -352,6 +376,12 @@ export const useHeaderNavigationLinks = () => {
352
376
  subtitle: t('header.products.analytics.items.subjects.subtitle'),
353
377
  icon: IconCompany,
354
378
  to: buildLocalizedUrl(locale, urls.analytics, PAGES.analytics.business)
379
+ },
380
+ {
381
+ title: t('header.products.analytics.items.demography.title'),
382
+ subtitle: t('header.products.analytics.items.demography.subtitle'),
383
+ icon: IconCompany,
384
+ to: buildLocalizedUrl(locale, urls.analytics, PAGES.analytics.demography)
355
385
  }
356
386
  ]
357
387
  },
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
7
+ <path d="M3.125 7.5H11.875" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M7.5 3.125L11.875 7.5L7.5 11.875" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
9
+ </svg>
10
+ </template>
11
+
12
+ <style scoped>
13
+
14
+ </style>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
7
+ <path d="M15 5.25H3C2.17157 5.25 1.5 5.92157 1.5 6.75V14.25C1.5 15.0784 2.17157 15.75 3 15.75H15C15.8284 15.75 16.5 15.0784 16.5 14.25V6.75C16.5 5.92157 15.8284 5.25 15 5.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M12 15.75V3.75C12 3.35218 11.842 2.97064 11.5607 2.68934C11.2794 2.40804 10.8978 2.25 10.5 2.25H7.5C7.10218 2.25 6.72064 2.40804 6.43934 2.68934C6.15804 2.97064 6 3.35218 6 3.75V15.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
9
+ </svg>
10
+ </template>
11
+
12
+ <style scoped>
13
+
14
+ </style>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+
3
+ </script>
4
+
5
+ <template>
6
+ <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
7
+ <path d="M14.25 12.75H15.75C16.2 12.75 16.5 12.45 16.5 12V9.75C16.5 9.075 15.975 8.475 15.375 8.325C14.025 7.95 12 7.5 12 7.5C12 7.5 11.025 6.45 10.35 5.775C9.975 5.475 9.525 5.25 9 5.25H3.75C3.3 5.25 2.925 5.55 2.7 5.925L1.65 8.1C1.55068 8.38967 1.5 8.69378 1.5 9V12C1.5 12.45 1.8 12.75 2.25 12.75H3.75" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
8
+ <path d="M5.25 14.25C6.07843 14.25 6.75 13.5784 6.75 12.75C6.75 11.9216 6.07843 11.25 5.25 11.25C4.42157 11.25 3.75 11.9216 3.75 12.75C3.75 13.5784 4.42157 14.25 5.25 14.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
9
+ <path d="M6.75 12.75H11.25" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
10
+ <path d="M12.75 14.25C13.5784 14.25 14.25 13.5784 14.25 12.75C14.25 11.9216 13.5784 11.25 12.75 11.25C11.9216 11.25 11.25 11.9216 11.25 12.75C11.25 13.5784 11.9216 14.25 12.75 14.25Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
11
+ </svg>
12
+ </template>
13
+
14
+ <style scoped>
15
+
16
+ </style>