adata-ui 2.1.39 → 2.1.40-beta.1
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.
- package/.playground/app.vue +102 -0
- package/components/elements/button-login/index.vue +6 -10
- package/components/features/color-mode/AColorMode.client.vue +74 -32
- package/components/features/dropdown/ADropdownV2.vue +141 -0
- package/components/features/lang-switcher/lang-switcher.vue +120 -40
- package/components/features/pk-mobile-services/APkMobileServices.vue +5 -27
- package/components/features//321/201hange-version/AChangeVersion.vue +1 -1
- package/components/navigation/header/AHeader.vue +56 -33
- package/components/navigation/header/AlmatyContacts.vue +1 -1
- package/components/navigation/header/CardGallery.vue +5 -3
- package/components/navigation/header/ContactMenu.vue +26 -92
- package/components/navigation/header/HeaderLink.vue +189 -215
- package/components/navigation/header/HeaderUsage.vue +125 -0
- package/components/navigation/header/NavList.vue +56 -91
- package/components/navigation/header/ProductMenu.vue +79 -127
- package/components/navigation/header/ProfileMenu.vue +131 -150
- package/components/navigation/header/SystemNotification.vue +110 -0
- package/components/navigation/mobile-navigation/AMobileNavigation.vue +23 -15
- package/components/navigation/pill-tabs/APillTabs.vue +7 -2
- package/components/overlays/tooltip/ATooltipV2.vue +233 -0
- package/components/overlays/tooltip/types.ts +26 -0
- package/components/overlays/tooltip/useTooltipTrigger.ts +101 -0
- package/composables/useActiveNavigation.ts +84 -0
- package/composables/useHeaderNavigationLinks.ts +14 -7
- package/icons/gauge.vue +17 -0
- package/icons/sun.vue +13 -3
- package/lang/en.ts +6 -0
- package/lang/kk.ts +6 -0
- package/lang/ru.ts +6 -0
- package/package.json +1 -1
- package/components/navigation/header/TopHeader.vue +0 -196
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { TooltipPlacement, TooltipTrigger } from './types'
|
|
3
|
+
import {
|
|
4
|
+
arrow as arrowMiddleware,
|
|
5
|
+
autoUpdate,
|
|
6
|
+
flip,
|
|
7
|
+
offset as offsetMiddleware,
|
|
8
|
+
shift,
|
|
9
|
+
useFloating,
|
|
10
|
+
} from '@floating-ui/vue'
|
|
11
|
+
import { onClickOutside, onKeyStroke } from '@vueuse/core'
|
|
12
|
+
import { twMerge } from 'tailwind-merge'
|
|
13
|
+
import { useTooltipTrigger } from './useTooltipTrigger'
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
/** Preferred side; auto-flips when there isn't room. */
|
|
17
|
+
placement?: TooltipPlacement
|
|
18
|
+
/** How the tooltip opens. `manual` is fully driven by `v-model:open`. */
|
|
19
|
+
trigger?: TooltipTrigger
|
|
20
|
+
/** Show a pointer arrow aimed at the trigger. */
|
|
21
|
+
arrow?: boolean
|
|
22
|
+
/** Gap between trigger and tooltip, in px. */
|
|
23
|
+
offset?: number
|
|
24
|
+
openDelay?: number
|
|
25
|
+
closeDelay?: number
|
|
26
|
+
/** Render through `<Teleport to="body">` to escape overflow/stacking contexts. */
|
|
27
|
+
teleport?: boolean
|
|
28
|
+
disabled?: boolean
|
|
29
|
+
zIndex?: number
|
|
30
|
+
/** Plain-text fallback used when the `content` slot is empty. */
|
|
31
|
+
text?: string
|
|
32
|
+
/** Extra classes merged onto the tooltip box (e.g. width/padding overrides). */
|
|
33
|
+
contentClass?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
defineOptions({ name: 'ATooltipV2', inheritAttrs: false })
|
|
37
|
+
|
|
38
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
39
|
+
placement: 'top',
|
|
40
|
+
trigger: 'hover',
|
|
41
|
+
arrow: false,
|
|
42
|
+
offset: 8,
|
|
43
|
+
openDelay: 0,
|
|
44
|
+
closeDelay: 0,
|
|
45
|
+
teleport: true,
|
|
46
|
+
disabled: false,
|
|
47
|
+
zIndex: 9999,
|
|
48
|
+
text: '',
|
|
49
|
+
contentClass: '',
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const open = defineModel<boolean>('open', { default: false })
|
|
53
|
+
|
|
54
|
+
const reference = ref<HTMLElement | null>(null)
|
|
55
|
+
const floating = ref<HTMLElement | null>(null)
|
|
56
|
+
const arrowRef = ref<HTMLElement | null>(null)
|
|
57
|
+
|
|
58
|
+
const tooltipId = `a-tooltip-v2-${useId()}`
|
|
59
|
+
|
|
60
|
+
const { listeners, close, clearTimers } = useTooltipTrigger({
|
|
61
|
+
open,
|
|
62
|
+
trigger: toRef(props, 'trigger'),
|
|
63
|
+
disabled: toRef(props, 'disabled'),
|
|
64
|
+
openDelay: toRef(props, 'openDelay'),
|
|
65
|
+
closeDelay: toRef(props, 'closeDelay'),
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const { x, y, strategy, middlewareData, placement: resolvedPlacement } = useFloating(reference, floating, {
|
|
69
|
+
placement: computed(() => props.placement),
|
|
70
|
+
strategy: 'fixed',
|
|
71
|
+
whileElementsMounted: autoUpdate,
|
|
72
|
+
middleware: computed(() => [
|
|
73
|
+
offsetMiddleware(props.offset),
|
|
74
|
+
flip(),
|
|
75
|
+
shift({ padding: 8 }),
|
|
76
|
+
...(props.arrow ? [arrowMiddleware({ element: arrowRef, padding: 6 })] : []),
|
|
77
|
+
]),
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const side = computed(() => resolvedPlacement.value.split('-')[0])
|
|
81
|
+
const opposite: Record<string, string> = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' }
|
|
82
|
+
|
|
83
|
+
// Grow the panel out of the edge nearest the trigger.
|
|
84
|
+
const transformOrigin = computed(() => {
|
|
85
|
+
const [main, align] = resolvedPlacement.value.split('-')
|
|
86
|
+
const anchor = opposite[main] ?? 'center'
|
|
87
|
+
if (main === 'left' || main === 'right') {
|
|
88
|
+
const v = align === 'start' ? 'top' : align === 'end' ? 'bottom' : 'center'
|
|
89
|
+
return `${anchor} ${v}`
|
|
90
|
+
}
|
|
91
|
+
const h = align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'
|
|
92
|
+
return `${h} ${anchor}`
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// The two outer edges of the rotated square form the visible point.
|
|
96
|
+
const arrowBorderClass = computed(() => {
|
|
97
|
+
switch (side.value) {
|
|
98
|
+
case 'top': return 'border-b border-r'
|
|
99
|
+
case 'bottom': return 'border-t border-l'
|
|
100
|
+
case 'left': return 'border-t border-r'
|
|
101
|
+
case 'right': return 'border-b border-l'
|
|
102
|
+
default: return ''
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const arrowStyle = computed<Record<string, string>>(() => {
|
|
107
|
+
const data = middlewareData.value.arrow
|
|
108
|
+
const staticSide = opposite[side.value]
|
|
109
|
+
const style: Record<string, string> = {}
|
|
110
|
+
if (data?.x != null) style.left = `${data.x}px`
|
|
111
|
+
if (data?.y != null) style.top = `${data.y}px`
|
|
112
|
+
if (staticSide) style[staticSide] = '-4px'
|
|
113
|
+
return style
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
const interactive = computed(() => props.trigger !== 'hover')
|
|
117
|
+
|
|
118
|
+
const boxClass = computed(() =>
|
|
119
|
+
twMerge(
|
|
120
|
+
'rounded-lg bg-white px-2.5 py-1.5 shadow-lg ring-1 ring-gray-200 dark:bg-gray-900 dark:ring-gray-700',
|
|
121
|
+
props.contentClass,
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
// Click mode dismisses on outside-click / Escape; hover leaves on its own; manual is parent-driven.
|
|
126
|
+
onClickOutside(
|
|
127
|
+
floating,
|
|
128
|
+
() => {
|
|
129
|
+
if (open.value && props.trigger === 'click') close()
|
|
130
|
+
},
|
|
131
|
+
{ ignore: [reference] },
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
onKeyStroke('Escape', () => {
|
|
135
|
+
if (open.value && props.trigger === 'click') close()
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
onUnmounted(() => clearTimers())
|
|
139
|
+
</script>
|
|
140
|
+
|
|
141
|
+
<template>
|
|
142
|
+
<span
|
|
143
|
+
ref="reference"
|
|
144
|
+
v-bind="$attrs"
|
|
145
|
+
class="inline-flex"
|
|
146
|
+
:aria-describedby="open ? tooltipId : undefined"
|
|
147
|
+
v-on="listeners"
|
|
148
|
+
>
|
|
149
|
+
<slot :open="open" />
|
|
150
|
+
</span>
|
|
151
|
+
|
|
152
|
+
<teleport
|
|
153
|
+
to="body"
|
|
154
|
+
:disabled="!teleport"
|
|
155
|
+
>
|
|
156
|
+
<transition
|
|
157
|
+
enter-active-class="a-tooltip-v2__enter-active"
|
|
158
|
+
enter-from-class="a-tooltip-v2__enter-from"
|
|
159
|
+
enter-to-class="a-tooltip-v2__enter-to"
|
|
160
|
+
leave-active-class="a-tooltip-v2__leave-active"
|
|
161
|
+
leave-from-class="a-tooltip-v2__leave-from"
|
|
162
|
+
leave-to-class="a-tooltip-v2__leave-to"
|
|
163
|
+
>
|
|
164
|
+
<div
|
|
165
|
+
v-if="open && !disabled"
|
|
166
|
+
:id="tooltipId"
|
|
167
|
+
ref="floating"
|
|
168
|
+
role="tooltip"
|
|
169
|
+
:class="[boxClass, interactive ? 'pointer-events-auto' : 'pointer-events-none']"
|
|
170
|
+
:style="{
|
|
171
|
+
position: strategy,
|
|
172
|
+
left: x != null ? `${x}px` : '0',
|
|
173
|
+
top: y != null ? `${y}px` : '0',
|
|
174
|
+
zIndex,
|
|
175
|
+
transformOrigin,
|
|
176
|
+
}"
|
|
177
|
+
>
|
|
178
|
+
<slot
|
|
179
|
+
name="content"
|
|
180
|
+
:close="close"
|
|
181
|
+
>
|
|
182
|
+
{{ text }}
|
|
183
|
+
</slot>
|
|
184
|
+
|
|
185
|
+
<span
|
|
186
|
+
v-if="arrow"
|
|
187
|
+
ref="arrowRef"
|
|
188
|
+
class="absolute size-2 rotate-45 border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900"
|
|
189
|
+
:class="arrowBorderClass"
|
|
190
|
+
:style="arrowStyle"
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
</transition>
|
|
194
|
+
</teleport>
|
|
195
|
+
</template>
|
|
196
|
+
|
|
197
|
+
<style scoped>
|
|
198
|
+
.a-tooltip-v2__enter-active {
|
|
199
|
+
transition:
|
|
200
|
+
opacity 160ms ease,
|
|
201
|
+
transform 200ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.a-tooltip-v2__leave-active {
|
|
205
|
+
transition:
|
|
206
|
+
opacity 120ms ease,
|
|
207
|
+
transform 140ms cubic-bezier(0.4, 0, 1, 1);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.a-tooltip-v2__enter-from,
|
|
211
|
+
.a-tooltip-v2__leave-to {
|
|
212
|
+
opacity: 0;
|
|
213
|
+
transform: translateY(-4px) scale(0.96);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.a-tooltip-v2__enter-to,
|
|
217
|
+
.a-tooltip-v2__leave-from {
|
|
218
|
+
opacity: 1;
|
|
219
|
+
transform: translateY(0) scale(1);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@media (prefers-reduced-motion: reduce) {
|
|
223
|
+
.a-tooltip-v2__enter-active,
|
|
224
|
+
.a-tooltip-v2__leave-active {
|
|
225
|
+
transition: opacity 120ms ease;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.a-tooltip-v2__enter-from,
|
|
229
|
+
.a-tooltip-v2__leave-to {
|
|
230
|
+
transform: none;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
</style>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Placement } from '@floating-ui/vue'
|
|
2
|
+
|
|
3
|
+
export type { Placement }
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Placement options spelled out as literals (mirrors Floating UI's `Placement`).
|
|
7
|
+
* Importing the package's `Placement` alias directly makes Vue's runtime prop
|
|
8
|
+
* inference fall back to `Object` and warn; a locally-resolvable union infers
|
|
9
|
+
* `String` correctly.
|
|
10
|
+
*/
|
|
11
|
+
export type TooltipPlacement
|
|
12
|
+
= | 'top'
|
|
13
|
+
| 'top-start'
|
|
14
|
+
| 'top-end'
|
|
15
|
+
| 'bottom'
|
|
16
|
+
| 'bottom-start'
|
|
17
|
+
| 'bottom-end'
|
|
18
|
+
| 'left'
|
|
19
|
+
| 'left-start'
|
|
20
|
+
| 'left-end'
|
|
21
|
+
| 'right'
|
|
22
|
+
| 'right-start'
|
|
23
|
+
| 'right-end'
|
|
24
|
+
|
|
25
|
+
/** How the tooltip is opened. `manual` is fully driven by `v-model:open`. */
|
|
26
|
+
export type TooltipTrigger = 'hover' | 'click' | 'manual'
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Ref } from 'vue'
|
|
2
|
+
import type { TooltipTrigger } from './types'
|
|
3
|
+
import { computed, watch } from 'vue'
|
|
4
|
+
|
|
5
|
+
interface UseTooltipTriggerOptions {
|
|
6
|
+
/** Visibility ref (the component's `v-model:open`). Mutated here. */
|
|
7
|
+
open: Ref<boolean>
|
|
8
|
+
trigger: Ref<TooltipTrigger>
|
|
9
|
+
disabled: Ref<boolean>
|
|
10
|
+
openDelay: Ref<number>
|
|
11
|
+
closeDelay: Ref<number>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Owns the open/close state machine for {@link ATooltipV2}: debounced show/hide
|
|
16
|
+
* and the per-mode DOM listeners. Kept separate from the SFC so each trigger
|
|
17
|
+
* style (hover/focus, click, manual) stays small and independently testable.
|
|
18
|
+
*/
|
|
19
|
+
export function useTooltipTrigger(options: UseTooltipTriggerOptions) {
|
|
20
|
+
const { open, trigger, disabled, openDelay, closeDelay } = options
|
|
21
|
+
|
|
22
|
+
let openTimer: ReturnType<typeof setTimeout> | null = null
|
|
23
|
+
let closeTimer: ReturnType<typeof setTimeout> | null = null
|
|
24
|
+
|
|
25
|
+
function clearOpenTimer() {
|
|
26
|
+
if (openTimer) {
|
|
27
|
+
clearTimeout(openTimer)
|
|
28
|
+
openTimer = null
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function clearCloseTimer() {
|
|
33
|
+
if (closeTimer) {
|
|
34
|
+
clearTimeout(closeTimer)
|
|
35
|
+
closeTimer = null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function clearTimers() {
|
|
40
|
+
clearOpenTimer()
|
|
41
|
+
clearCloseTimer()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function show() {
|
|
45
|
+
if (disabled.value || open.value) return
|
|
46
|
+
clearCloseTimer()
|
|
47
|
+
if (openDelay.value > 0) {
|
|
48
|
+
openTimer = setTimeout(() => {
|
|
49
|
+
open.value = true
|
|
50
|
+
openTimer = null
|
|
51
|
+
}, openDelay.value)
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
open.value = true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function hide() {
|
|
59
|
+
clearOpenTimer()
|
|
60
|
+
if (!open.value) return
|
|
61
|
+
if (closeDelay.value > 0) {
|
|
62
|
+
closeTimer = setTimeout(() => {
|
|
63
|
+
open.value = false
|
|
64
|
+
closeTimer = null
|
|
65
|
+
}, closeDelay.value)
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
open.value = false
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function toggle() {
|
|
73
|
+
if (open.value) hide()
|
|
74
|
+
else show()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function close() {
|
|
78
|
+
clearTimers()
|
|
79
|
+
open.value = false
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Force-close if disabled while visible.
|
|
83
|
+
watch(disabled, (value) => {
|
|
84
|
+
if (value) close()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Listeners bound on the trigger wrapper via `v-on`, selected by mode.
|
|
88
|
+
const listeners = computed<Record<string, () => void>>(() => {
|
|
89
|
+
if (disabled.value) return {}
|
|
90
|
+
switch (trigger.value) {
|
|
91
|
+
case 'hover':
|
|
92
|
+
return { mouseenter: show, mouseleave: hide, focusin: show, focusout: hide }
|
|
93
|
+
case 'click':
|
|
94
|
+
return { click: toggle }
|
|
95
|
+
default:
|
|
96
|
+
return {}
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
return { show, hide, toggle, close, clearTimers, listeners }
|
|
101
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Active-state detection for the products mega-menu.
|
|
2
|
+
//
|
|
3
|
+
// Two levels of "active":
|
|
4
|
+
// 1. activeModule — the current host matches one of the module's hosts
|
|
5
|
+
// (host ≠ module key: e.g. the `fines` module lives on avto.*.kz,
|
|
6
|
+
// and `tenders` spans both zakupki.*.kz and tender.*.kz).
|
|
7
|
+
// 2. activeService — within the active module, the current page matches a
|
|
8
|
+
// concrete item link (`/`, `/unload`, `/foreign`, …).
|
|
9
|
+
|
|
10
|
+
const LOCALE_SEGMENTS = new Set(['kk', 'en'])
|
|
11
|
+
|
|
12
|
+
interface NavTarget { to: string }
|
|
13
|
+
interface NavModule { link: string, items: NavTarget[] }
|
|
14
|
+
interface NormalizedUrl { host: string, key: string }
|
|
15
|
+
|
|
16
|
+
function safeUrl(href: string): URL | null {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(href)
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Reduce a URL to a comparable identity: host + locale-stripped path + query.
|
|
26
|
+
// The query is kept because it can be significant (fines main is `/?check_fines=true`).
|
|
27
|
+
function normalize(href: string): NormalizedUrl | null {
|
|
28
|
+
const url = safeUrl(href)
|
|
29
|
+
if (!url) return null
|
|
30
|
+
|
|
31
|
+
const segments = url.pathname
|
|
32
|
+
.split('/')
|
|
33
|
+
.filter(segment => segment && !LOCALE_SEGMENTS.has(segment))
|
|
34
|
+
|
|
35
|
+
const path = `/${segments.join('/')}`
|
|
36
|
+
return { host: url.host, key: path + url.search }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// A "root" target has no path segments (e.g. `/` or `/?check_fines=true`).
|
|
40
|
+
// Roots must match exactly, otherwise their prefix would light up every sub-page.
|
|
41
|
+
function isRoot(key: string): boolean {
|
|
42
|
+
return key === '/' || key.startsWith('/?')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function useActiveNavigation() {
|
|
46
|
+
const route = useRoute()
|
|
47
|
+
|
|
48
|
+
// Recompute on every SPA navigation. Host stays constant within an app, so we
|
|
49
|
+
// read it from the request URL (SSR-safe); the path/query come from the route.
|
|
50
|
+
const current = computed<NormalizedUrl | null>(() => {
|
|
51
|
+
const host = useRequestURL().host
|
|
52
|
+
return normalize(`https://${host}${route.fullPath}`)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
function isActiveModule(module: NavModule): boolean {
|
|
56
|
+
if (!current.value) return false
|
|
57
|
+
|
|
58
|
+
const hosts = new Set<string>()
|
|
59
|
+
const link = normalize(module.link)
|
|
60
|
+
if (link) hosts.add(link.host)
|
|
61
|
+
for (const item of module.items) {
|
|
62
|
+
const item_url = normalize(item.to)
|
|
63
|
+
if (item_url) hosts.add(item_url.host)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return hosts.has(current.value.host)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function isActiveService(itemTo: string): boolean {
|
|
70
|
+
const cur = current.value
|
|
71
|
+
const item = normalize(itemTo)
|
|
72
|
+
if (!cur || !item || cur.host !== item.host) return false
|
|
73
|
+
|
|
74
|
+
// The car-check page redirects to a `car-result` URL; keep its item lit.
|
|
75
|
+
if (item.key.includes('check-car') && cur.key.includes('car-result')) return true
|
|
76
|
+
|
|
77
|
+
if (cur.key === item.key) return true
|
|
78
|
+
if (isRoot(item.key)) return false
|
|
79
|
+
|
|
80
|
+
return cur.key.startsWith(item.key)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return { isActiveModule, isActiveService }
|
|
84
|
+
}
|
|
@@ -367,22 +367,26 @@ export const useHeaderMenuLinks = () => {
|
|
|
367
367
|
{
|
|
368
368
|
title: t('header.profile.menu.personalInfo'),
|
|
369
369
|
icon: IconProfile,
|
|
370
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.index)
|
|
370
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.index),
|
|
371
|
+
dataTestId: 'dropdown-profile-button'
|
|
371
372
|
},
|
|
372
373
|
{
|
|
373
374
|
title: t('header.profile.menu.security'),
|
|
374
375
|
icon: IconLock,
|
|
375
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.security)
|
|
376
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.security),
|
|
377
|
+
dataTestId: 'dropdown-profile-change-password-button'
|
|
376
378
|
},
|
|
377
379
|
{
|
|
378
380
|
title: t('header.profile.menu.paymentHistory'),
|
|
379
381
|
icon: IconReceipt,
|
|
380
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.paymentHistory)
|
|
382
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.paymentHistory),
|
|
383
|
+
dataTestId: 'dropdown-profile-payment-story-button'
|
|
381
384
|
},
|
|
382
385
|
{
|
|
383
386
|
title: t('header.profile.menu.favourites'),
|
|
384
387
|
icon: IconFavorite,
|
|
385
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.favourites)
|
|
388
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.favourites),
|
|
389
|
+
dataTestId: 'dropdown-favourites-button'
|
|
386
390
|
},
|
|
387
391
|
// {
|
|
388
392
|
// title: t('header.profile.menu.myReports'),
|
|
@@ -392,17 +396,20 @@ export const useHeaderMenuLinks = () => {
|
|
|
392
396
|
{
|
|
393
397
|
title: t('header.profile.menu.browsingHistory'),
|
|
394
398
|
icon: IconHistory,
|
|
395
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.browsingHistory)
|
|
399
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.browsingHistory),
|
|
400
|
+
dataTestId: 'dropdown-profile-view-history-button'
|
|
396
401
|
},
|
|
397
402
|
{
|
|
398
403
|
title: t('header.profile.menu.myGroups'),
|
|
399
404
|
icon: IconUsers,
|
|
400
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.myGroups)
|
|
405
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.myGroups),
|
|
406
|
+
dataTestId: 'dropdown-profile-my-groups-button'
|
|
401
407
|
},
|
|
402
408
|
{
|
|
403
409
|
title: t('header.profile.menu.notes'),
|
|
404
410
|
icon: IconMessage,
|
|
405
|
-
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.notes)
|
|
411
|
+
to: buildLocalizedUrl(locale.value, urls.landing, PAGES.profile.notes),
|
|
412
|
+
dataTestId: 'dropdown-profile-notes-button'
|
|
406
413
|
}
|
|
407
414
|
]
|
|
408
415
|
}
|
package/icons/gauge.vue
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg
|
|
3
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
4
|
+
width="1em"
|
|
5
|
+
height="1em"
|
|
6
|
+
viewBox="0 0 24 24"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
fill="none"
|
|
10
|
+
stroke="currentColor"
|
|
11
|
+
stroke-linecap="round"
|
|
12
|
+
stroke-linejoin="round"
|
|
13
|
+
stroke-width="2"
|
|
14
|
+
d="m12 14l4-4M3.34 19a10 10 0 1 1 17.32 0"
|
|
15
|
+
/>
|
|
16
|
+
</svg>
|
|
17
|
+
</template>
|
package/icons/sun.vue
CHANGED
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
</script>
|
|
4
4
|
|
|
5
5
|
<template>
|
|
6
|
-
<svg
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
<svg
|
|
7
|
+
width="16"
|
|
8
|
+
height="16"
|
|
9
|
+
viewBox="0 0 16 16"
|
|
10
|
+
fill="none"
|
|
11
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
12
|
+
>
|
|
13
|
+
<path
|
|
14
|
+
opacity="0.7"
|
|
15
|
+
d="M7.99998 12.6666C10.5773 12.6666 12.6666 10.5772 12.6666 7.99992C12.6666 5.42259 10.5773 3.33325 7.99998 3.33325C5.42265 3.33325 3.33331 5.42259 3.33331 7.99992C3.33331 10.5772 5.42265 12.6666 7.99998 12.6666Z"
|
|
16
|
+
fill="#FBC920"
|
|
17
|
+
/>
|
|
18
|
+
<path d="M8.00002 15.3067C7.63335 15.3067 7.33335 15.0334 7.33335 14.6667V14.6134C7.33335 14.2467 7.63335 13.9467 8.00002 13.9467C8.36669 13.9467 8.66669 14.2467 8.66669 14.6134C8.66669 14.9801 8.36669 15.3067 8.00002 15.3067ZM12.76 13.4267C12.5867 13.4267 12.42 13.3601 12.2867 13.2334L12.2 13.1467C11.94 12.8867 11.94 12.4667 12.2 12.2067C12.46 11.9467 12.88 11.9467 13.14 12.2067L13.2267 12.2934C13.4867 12.5534 13.4867 12.9734 13.2267 13.2334C13.1 13.3601 12.9334 13.4267 12.76 13.4267ZM3.24002 13.4267C3.06669 13.4267 2.90002 13.3601 2.76669 13.2334C2.50669 12.9734 2.50669 12.5534 2.76669 12.2934L2.85335 12.2067C3.11335 11.9467 3.53335 11.9467 3.79335 12.2067C4.05335 12.4667 4.05335 12.8867 3.79335 13.1467L3.70669 13.2334C3.58002 13.3601 3.40669 13.4267 3.24002 13.4267ZM14.6667 8.66675H14.6134C14.2467 8.66675 13.9467 8.36675 13.9467 8.00008C13.9467 7.63341 14.2467 7.33342 14.6134 7.33342C14.98 7.33342 15.3067 7.63341 15.3067 8.00008C15.3067 8.36675 15.0334 8.66675 14.6667 8.66675ZM1.38669 8.66675H1.33335C0.966687 8.66675 0.666687 8.36675 0.666687 8.00008C0.666687 7.63341 0.966687 7.33342 1.33335 7.33342C1.70002 7.33342 2.02669 7.63341 2.02669 8.00008C2.02669 8.36675 1.75335 8.66675 1.38669 8.66675ZM12.6734 3.99341C12.5 3.99341 12.3334 3.92675 12.2 3.80008C11.94 3.54008 11.94 3.12008 12.2 2.86008L12.2867 2.77341C12.5467 2.51341 12.9667 2.51341 13.2267 2.77341C13.4867 3.03341 13.4867 3.45341 13.2267 3.71341L13.14 3.80008C13.0134 3.92675 12.8467 3.99341 12.6734 3.99341ZM3.32669 3.99341C3.15335 3.99341 2.98669 3.92675 2.85335 3.80008L2.76669 3.70675C2.50669 3.44675 2.50669 3.02675 2.76669 2.76675C3.02669 2.50675 3.44669 2.50675 3.70669 2.76675L3.79335 2.85342C4.05335 3.11342 4.05335 3.53341 3.79335 3.79341C3.66669 3.92675 3.49335 3.99341 3.32669 3.99341ZM8.00002 2.02675C7.63335 2.02675 7.33335 1.75341 7.33335 1.38675V1.33341C7.33335 0.966748 7.63335 0.666748 8.00002 0.666748C8.36669 0.666748 8.66669 0.966748 8.66669 1.33341C8.66669 1.70008 8.36669 2.02675 8.00002 2.02675Z" fill="#FBC920" />
|
|
9
19
|
</svg>
|
|
10
20
|
</template>
|
|
11
21
|
|
package/lang/en.ts
CHANGED
|
@@ -27,6 +27,10 @@ const EnLocale: RuLocale = {
|
|
|
27
27
|
requestLimit: 'Daily request limit',
|
|
28
28
|
daysLeft: 'Days left',
|
|
29
29
|
},
|
|
30
|
+
usage: {
|
|
31
|
+
requests: 'Requests',
|
|
32
|
+
days: 'days',
|
|
33
|
+
},
|
|
30
34
|
profile: {
|
|
31
35
|
tariff: 'Tariff',
|
|
32
36
|
balance: 'Balance:',
|
|
@@ -268,6 +272,8 @@ const EnLocale: RuLocale = {
|
|
|
268
272
|
},
|
|
269
273
|
edo: {
|
|
270
274
|
label: 'EDM',
|
|
275
|
+
heroSubtitle: 'Templates · AI assistant · Signatures · Voice input',
|
|
276
|
+
heroCta: 'Open EDO',
|
|
271
277
|
items: {
|
|
272
278
|
l: {
|
|
273
279
|
t: 'Document Flow',
|
package/lang/kk.ts
CHANGED
|
@@ -27,6 +27,10 @@ const KkLocale: RuLocale = {
|
|
|
27
27
|
requestLimit: 'Күнделікті сұраныс лимиті',
|
|
28
28
|
daysLeft: 'Қалған күндер',
|
|
29
29
|
},
|
|
30
|
+
usage: {
|
|
31
|
+
requests: 'Сұраныстар',
|
|
32
|
+
days: 'күн',
|
|
33
|
+
},
|
|
30
34
|
profile: {
|
|
31
35
|
tariff: 'Тариф',
|
|
32
36
|
balance: 'Баланс:',
|
|
@@ -268,6 +272,8 @@ const KkLocale: RuLocale = {
|
|
|
268
272
|
},
|
|
269
273
|
edo: {
|
|
270
274
|
label: 'ЭҚА',
|
|
275
|
+
heroSubtitle: 'Үлгілер · AI-ассистент · ЭЦҚ · Дауыспен енгізу',
|
|
276
|
+
heroCta: 'EDO-ды ашу',
|
|
271
277
|
items: {
|
|
272
278
|
l: {
|
|
273
279
|
t: 'Құжат айналымы',
|
package/lang/ru.ts
CHANGED
|
@@ -23,6 +23,10 @@ const RuLocale = {
|
|
|
23
23
|
requestLimit: 'Cуточный лимит запросов',
|
|
24
24
|
daysLeft: 'Остаток дней',
|
|
25
25
|
},
|
|
26
|
+
usage: {
|
|
27
|
+
requests: 'Запросы',
|
|
28
|
+
days: 'дн.',
|
|
29
|
+
},
|
|
26
30
|
profile: {
|
|
27
31
|
tariff: 'Тариф',
|
|
28
32
|
balance: 'Баланс:',
|
|
@@ -269,6 +273,8 @@ const RuLocale = {
|
|
|
269
273
|
},
|
|
270
274
|
edo: {
|
|
271
275
|
label: 'ЭДО',
|
|
276
|
+
heroSubtitle: 'Шаблоны · AI-ассистент · ЭЦП · Голосовой ввод',
|
|
277
|
+
heroCta: 'Открыть EDO',
|
|
272
278
|
items: {
|
|
273
279
|
l: {
|
|
274
280
|
t: 'Документооборот',
|